الربط بتطبيق وسائط

هناك طريقتان للاتصال بتطبيق وسائط:

  1. MediaController
  2. MediaBrowser

MediaController

تتفاعل وحدة التحكّم في الوسائط مع جلسة وسائط للاستعلام عن تشغيل تطبيق وسائط والتحكّم فيه. في Media3، تنفّذ واجهة برمجة التطبيقات MediaController واجهة Player. تشمل أمثلة تطبيقات العميل التي تستخدم عنصر تحكّم في الوسائط ما يلي:

يمكن أن تكون وحدة التحكّم في الوسائط مفيدة أيضًا داخل تطبيق وسائط، مثلاً إذا كان مشغّل الوسائط وجلسة الوسائط موجودَين في Service منفصل عن Activity أو Fragment مع واجهة المستخدم.

إنشاء MediaController

لإنشاء MediaController، ابدأ بإنشاء SessionToken لـ MediaSession المقابلة. يمكن أن يكون الأسلوب onStart() في Activity أو Fragment مكانًا جيدًا لذلك.

Kotlin

val sessionToken = SessionToken(context, ComponentName(context, PlaybackService::class.java))

Java

SessionToken sessionToken =
    new SessionToken(context, new ComponentName(context, PlaybackService.class));

يؤدي استخدام SessionToken هذا لإنشاء MediaController إلى ربط عنصر التحكّم بالجلسة المحدّدة. يحدث ذلك بشكل غير متزامن، لذا عليك الاستماع إلى النتيجة واستخدامها عندما تصبح متاحة.

Kotlin

val controllerFuture = MediaController.Builder(context, sessionToken).buildAsync()
controllerFuture.addListener(
  {
    // MediaController is available here with controllerFuture.get()
  },
  MoreExecutors.directExecutor(),
)

Java

ListenableFuture<MediaController> controllerFuture =
    new MediaController.Builder(context, sessionToken).buildAsync();
controllerFuture.addListener(
    () -> {
      // MediaController is available here with controllerFuture.get()
    },
    MoreExecutors.directExecutor());

استخدام MediaController

تنفّذ MediaController واجهة Player، لذا يمكنك استخدام الأوامر المحدّدة في الواجهة للتحكّم في تشغيل MediaSession المتصلة. يعني ذلك أنّ استدعاء play() على MediaController سيُرسِل الأمر إلى MediaSession المتصلة، التي ستفوّض بدورها الأمر إلى Player الأساسي.

يمكنك إضافة Player.Listener إلى عنصر التحكّم للاستماع إلى التغييرات في Player الحالة. يُرجى الرجوع إلى دليل أحداث مشغّل الوسائط لمزيد من التفاصيل حول استخدام Player.Listener.

تحدّد واجهة MediaController.Listener عمليات ردّ إضافية للأحداث والأوامر المخصّصة من MediaSession المتصلة. تشمل الأمثلة onCustomCommand() عندما تُرسِل الجلسة أمرًا مخصّصًا، onAvailableSessionCommandsChanged() عندما تغيّر الجلسة أوامر الجلسة المتاحة أو onDisconnected() عندما يتم قطع اتصال عنصر التحكّم بالجلسة.

يمكن ضبط MediaController.Listener عند إنشاء عنصر التحكّم باستخدام Builder:

Kotlin

val controllerFuture =
  MediaController.Builder(context, sessionToken)
    .setListener(
      object : MediaController.Listener {
        override fun onCustomCommand(
          controller: MediaController,
          command: SessionCommand,
          args: Bundle,
        ): ListenableFuture<SessionResult> {
          // Handle custom command.
          return Futures.immediateFuture(SessionResult(SessionResult.RESULT_SUCCESS))
        }

        override fun onDisconnected(controller: MediaController) {
          // Handle disconnection.
        }
      }
    )
    .buildAsync()

Java

ListenableFuture<MediaController> controllerFuture =
    new MediaController.Builder(context, sessionToken)
        .setListener(
            new MediaController.Listener() {
              @Override
              public ListenableFuture<SessionResult> onCustomCommand(
                  MediaController controller, SessionCommand command, Bundle args) {
                // Handle custom command.
                return Futures.immediateFuture(new SessionResult(SessionResult.RESULT_SUCCESS));
              }

              @Override
              public void onDisconnected(MediaController controller) {
                // Handle disconnection.
              }
            })
        .buildAsync();

كما هو الحال مع المكوّنات الأخرى، تذكَّر إيقاف MediaController عندما لا يعود مطلوبًا، مثلاً في الأسلوب onStop() من Activity أو Fragment.

Kotlin

MediaController.releaseFuture(controllerFuture)

Java

MediaController.releaseFuture(controllerFuture);

سيستمر إيقاف عنصر التحكّم في إرسال جميع الأوامر المعلقة التي تم إرسالها إلى الجلسة، ولن يتم إلغاء ربط عنصر التحكّم بخدمة الجلسة إلا بعد معالجة هذه الأوامر أو بعد انتهاء مهلة، أيهما يحدث أولاً.

MediaBrowser

يستند MediaBrowser إلى الإمكانات التي يوفّرها MediaController ليتيح أيضًا تصفّح مكتبة الوسائط التي يوفّرها MediaLibraryService في تطبيق وسائط.

إنشاء MediaBrowser

Kotlin

val browserFuture = MediaBrowser.Builder(context, sessionToken).buildAsync()
browserFuture.addListener(
  {
    // MediaBrowser is available here with browserFuture.get()
  },
  MoreExecutors.directExecutor(),
)

Java

ListenableFuture<MediaBrowser> browserFuture =
    new MediaBrowser.Builder(context, sessionToken).buildAsync();
browserFuture.addListener(
    () -> {
      // MediaBrowser is available here with browserFuture.get()
    },
    MoreExecutors.directExecutor());

استخدام MediaBrowser

لبدء تصفّح مكتبة محتوى تطبيق الوسائط، عليك أولاً استرداد العقدة الجذرية باستخدام getLibraryRoot():

Kotlin

// Get the library root to start browsing the library tree.
val rootFuture = mediaBrowser.getLibraryRoot(/* params= */ null)
rootFuture.addListener(
  {
    // Root node MediaItem is available here with rootFuture.get().value
  },
  MoreExecutors.directExecutor(),
)

Java

// Get the library root to start browsing the library tree.
ListenableFuture<LibraryResult<MediaItem>> rootFuture =
    mediaBrowser.getLibraryRoot(/* params= */ null);
rootFuture.addListener(
    () -> {
      // Root node MediaItem is available here with rootFuture.get().value
    },
    MoreExecutors.directExecutor());

يمكنك بعد ذلك الانتقال خلال مكتبة الوسائط من خلال استرداد العناصر الفرعية لـ MediaItem في المكتبة باستخدام getChildren(). على سبيل المثال، لاسترداد العناصر الفرعية لـ MediaItem في العقدة الجذرية:

Kotlin

// Get the library root to start browsing the library tree.
val childrenFuture = mediaBrowser.getChildren(rootMediaItem.mediaId, 0, Int.MAX_VALUE, null)
childrenFuture.addListener(
  {
    // List of children MediaItem nodes is available here with
    // childrenFuture.get().value
  },
  MoreExecutors.directExecutor(),
)

Java

ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> childrenFuture =
    mediaBrowser.getChildren(rootMediaItem.mediaId, 0, Integer.MAX_VALUE, null);
childrenFuture.addListener(
    () -> {
      // List of children MediaItem nodes is available here with
      // childrenFuture.get().value
    },
    MoreExecutors.directExecutor());

عرض عناصر التحكّم في التشغيل لتطبيق موسيقى آخر

عند عرض عناصر التحكّم في واجهة المستخدم التي تتضمّن أزرارًا لتطبيق موسيقى آخر، من المهم اتّباع الإعدادات المفضّلة المعلَنة لأزرار الوسائط في هذا التطبيق.

لحلّ الإعدادات المفضّلة للتطبيق مع القيود والمتطلبات الخاصة بواجهة المستخدم، استخدِم CommandButton.DisplayConstraints. يمكنك تحديد الحدود و القيود التي يمكن أن تنفّذها واجهة المستخدم، وresolve الأسلوب يوفّر قائمة نهائية بالأزرار التي سيتم عرضها مع الرمز والموضع و الإجراء المقصود. إذا نقر المستخدم على أحد هذه الأزرار، يمكنك استخدام CommandButton.executeAction لتفعيل الإجراء المرتبط في تطبيق الوسائط.

Kotlin

// Get media button preferences from media app
val mediaButtonPreferences = controller.getMediaButtonPreferences()
// Declare constraints of UI (example: limit overflow button to one)
val displayConstraints =
  DisplayConstraints.Builder().setMaxButtonsForSlot(CommandButton.SLOT_OVERFLOW, 1).build()
// Resolve media app preferences with constraints
val resolvedButtons = displayConstraints.resolve(mediaButtonPreferences, controller)
// Display buttons in UI
for (button in resolvedButtons) {
  generateUiButton(
    uiPosition = button.slots[0],
    icon = getIconRes(button.icon),
    onClick = { button.executeAction(controller) },
  )
}

Java

// Get media button preferences from media app
List<CommandButton> mediaButtonPreferences = controller.getMediaButtonPreferences();
// Declare constraints of UI (example: limit overflow button to one)
DisplayConstraints displayConstraints =
    new DisplayConstraints.Builder()
        .setMaxButtonsForSlot(CommandButton.SLOT_OVERFLOW, 1)
        .build();
// Resolve media app preferences with constraints
List<CommandButton> resolvedButtons =
    displayConstraints.resolve(mediaButtonPreferences, controller);
// Display buttons in UI
for (CommandButton button : resolvedButtons) {
  generateUiButton(
      /* uiPosition= */ button.slots.get(0),
      /* icon= */ getIconRes(button.icon),
      /* onClick= */ () -> button.executeAction(controller));
}