تنظيم صفحاتك في مجموعات
يمكنك حفظ المحتوى وتصنيفه حسب إعداداتك المفضّلة.
هناك طريقتان للاتصال بتطبيق وسائط:
MediaController
MediaBrowser
MediaController
يتفاعل عنصر التحكّم في الوسائط مع جلسة وسائط للاستعلام عن تشغيل تطبيق وسائط والتحكّم فيه. في Media3، تنفّذ واجهة برمجة التطبيقات MediaController واجهة Player. في ما يلي أمثلة على تطبيقات العميل التي تستخدم أداة تحكّم في الوسائط:
يمكن أن يكون عنصر التحكّم في الوسائط مفيدًا أيضًا داخل تطبيق وسائط، مثلاً إذا كان مشغّل الوسائط وجلسة الوسائط في Service منفصلَين عن Activity أو Fragment مع واجهة المستخدم.
إنشاء MediaController
لإنشاء MediaController، ابدأ بإنشاء SessionToken
لـ MediaSession المقابل. يمكنك استخدام طريقة onStart() في Activity أو Fragment لهذا الغرض.
يؤدي استخدام SessionToken هذا لإنشاء MediaController إلى ربط وحدة التحكّم بالجلسة المحدّدة. يتم تنفيذ هذا الإجراء بشكل غير متزامن، لذا عليك الاستماع إلى النتيجة واستخدامها عند توفّرها.
Kotlin
valcontrollerFuture=MediaController.Builder(context,sessionToken).buildAsync()controllerFuture.addListener({// MediaController is available here with controllerFuture.get()},MoreExecutors.directExecutor())
Java
ListenableFuture<MediaController>controllerFuture=newMediaController.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:
كما هو الحال مع المكوّنات الأخرى، تذكَّر إصدار MediaController عندما لا تكون هناك حاجة إليه، مثلاً في طريقة onStop() الخاصة بـ Activity أو Fragment.
Kotlin
MediaController.releaseFuture(controllerFuture)
Java
MediaController.releaseFuture(controllerFuture);
سيؤدي تحرير وحدة التحكّم إلى إرسال جميع الأوامر المعلقة إلى الجلسة، ولن يتم إلغاء ربطها بخدمة الجلسة إلا بعد معالجة هذه الأوامر أو بعد انتهاء مهلة زمنية، أيهما أقرب.
MediaBrowser
تستند MediaBrowser إلى الإمكانات التي توفّرها MediaController، كما تتيح تصفّح مكتبة الوسائط التي يوفّرها MediaLibraryService لتطبيق وسائط.
إنشاء MediaBrowser
Kotlin
valbrowserFuture=MediaBrowser.Builder(context,sessionToken).buildAsync()browserFuture.addListener({// MediaBrowser is available here with browserFuture.get()},MoreExecutors.directExecutor())
Java
ListenableFuture<MediaBrowser>browserFuture=newMediaBrowser.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.valrootFuture=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.valchildrenFuture=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 قائمة محددة بالأزرار التي سيتم عرضها مع الرمز والموضع والإجراء المقصود.
يخضع كل من المحتوى وعيّنات التعليمات البرمجية في هذه الصفحة للتراخيص الموضحّة في ترخيص استخدام المحتوى. إنّ Java وOpenJDK هما علامتان تجاريتان مسجَّلتان لشركة Oracle و/أو الشركات التابعة لها.
تاريخ التعديل الأخير: 2025-08-27 (حسب التوقيت العالمي المتفَّق عليه)
[[["يسهُل فهم المحتوى.","easyToUnderstand","thumb-up"],["ساعَدني المحتوى في حلّ مشكلتي.","solvedMyProblem","thumb-up"],["غير ذلك","otherUp","thumb-up"]],[["لا يحتوي على المعلومات التي أحتاج إليها.","missingTheInformationINeed","thumb-down"],["الخطوات معقدة للغاية / كثيرة جدًا.","tooComplicatedTooManySteps","thumb-down"],["المحتوى قديم.","outOfDate","thumb-down"],["ثمة مشكلة في الترجمة.","translationIssue","thumb-down"],["مشكلة في العيّنات / التعليمات البرمجية","samplesCodeIssue","thumb-down"],["غير ذلك","otherDown","thumb-down"]],["تاريخ التعديل الأخير: 2025-08-27 (حسب التوقيت العالمي المتفَّق عليه)"],[],[],null,["# Connect to a media app\n\nThere are two ways to connect to a Media app:\n\n1. `MediaController`\n2. `MediaBrowser`\n\n`MediaController`\n-----------------\n\nA media controller interacts with a media session to query and control a media\napp's playback. In Media3, the [`MediaController`](/reference/kotlin/androidx/media3/session/MediaController)\nAPI implements the `Player` interface. Examples of client apps that use a media\ncontroller include:\n\n- [Android system media controls](/media/implement/surfaces/mobile)\n- Android Wear OS companion app\n- [Android Auto and Automotive OS](/training/cars/media)\n- Voice assistants, like [Google Assistant](/media/implement/assistant)\n- The [Media Controller Test app](/media/optimize/mct)\n\nA media controller can also be useful within a media app, for example if the\nplayer and media session live in a `Service` separate from the `Activity` or\n`Fragment` with the UI.\n\n### Create a `MediaController`\n\nTo create a `MediaController`, start by creating a `SessionToken` for the\ncorresponding `MediaSession`. The `onStart()` method of your `Activity` or\n`Fragment` can be a good place for this. \n\n### Kotlin\n\n val sessionToken =\n SessionToken(context, ComponentName(context, PlaybackService::class.java))\n\n### Java\n\n SessionToken sessionToken =\n new SessionToken(context, new ComponentName(context, PlaybackService.class));\n\n\u003cbr /\u003e\n\nUsing this `SessionToken` to then build a `MediaController` connects the\ncontroller to the given session. This takes place asynchronously, so you should\nlisten for the result and use it when available. \n\n### Kotlin\n\n val controllerFuture =\n MediaController.Builder(context, sessionToken).buildAsync()\n controllerFuture.addListener({\n // MediaController is available here with controllerFuture.get()\n }, MoreExecutors.directExecutor())\n\n### Java\n\n ListenableFuture\u003cMediaController\u003e controllerFuture =\n new MediaController.Builder(context, sessionToken).buildAsync();\n controllerFuture.addListener(() -\u003e {\n // MediaController is available here with controllerFuture.get()\n }, MoreExecutors.directExecutor());\n\n\u003cbr /\u003e\n\n| **Note:** Use `ContextCompat.getMainExecutor()` instead of `MoreExecutors.directExecutor()` in case you run your service in another process than the UI.\n| **Note:** Apps targeting SDK level 30 or higher must include a `\u003cqueries\u003e` element in their manifest to connect to a different app's `MediaSessionService` (or similar component). Refer to the [package visibility](/training/package-visibility) guide for further details.\n\n### Use a `MediaController`\n\n`MediaController` implements the `Player` interface, so you can use the commands\ndefined in the interface to control playback of the connected `MediaSession`.\nThis is to say that calling `play()` on a `MediaController` will send the\ncommand to the connected `MediaSession`, which will subsequently delegate the\ncommand to its underlying `Player`.\n| **Tip:** A media controller implements the `Player` interface, and as such you can use it within your UI as a `Player`.\n\nYou can add a `Player.Listener` to the controller to listen for changes in the\n`Player` state. Refer to the [Player events](/guide/topics/media/exoplayer/listening-to-player-events) guide for more details on using a\n`Player.Listener`.\n\nThe `MediaController.Listener` interface defines additional callbacks for events\nand custom commands from the connected `MediaSession`. Examples are\n[`onCustomCommand()`](/reference/kotlin/androidx/media3/session/MediaController.Listener#onCustomCommand(androidx.media3.session.MediaController,androidx.media3.session.SessionCommand,android.os.Bundle)) when the session sends a custom command,\n[`onAvailableSessionCommandsChanged()`](/reference/kotlin/androidx/media3/session/MediaController.Listener#onAvailableSessionCommandsChanged(androidx.media3.session.MediaController,androidx.media3.session.SessionCommands)) when the session changes the available\nsession commands or [`onDisconnected()`](/reference/kotlin/androidx/media3/session/MediaController.Listener#onDisconnected(androidx.media3.session.MediaController)) when the controller is disconnected\nfrom the session.\n\nA `MediaController.Listener` can be set when building the controller with a\n`Builder`: \n\n### Kotlin\n\n MediaController.Builder(context, sessionToken)\n .setListener(\n object : MediaController.Listener {\n override fun onCustomCommand(\n controller: MediaController,\n command: SessionCommand,\n args: Bundle,\n ): ListenableFuture\u003cSessionResult\u003e {\n // Handle custom command.\n return Futures.immediateFuture(SessionResult(SessionResult.RESULT_SUCCESS))\n }\n\n override fun onDisconnected(controller: MediaController) {\n // Handle disconnection.\n }\n }\n )\n .buildAsync()\n\n### Java\n\n new MediaController.Builder(context, sessionToken)\n .setListener(\n new MediaController.Listener() {\n @Override\n public ListenableFuture\u003cSessionResult\u003e onCustomCommand(\n MediaController controller, SessionCommand command, Bundle args) {\n // Handle custom command.\n return Futures.immediateFuture(new SessionResult(SessionResult.RESULT_SUCCESS));\n }\n\n @Override\n public void onDisconnected(MediaController controller) {\n // Handle disconnection.\n }\n })\n .buildAsync();\n\n\u003cbr /\u003e\n\nAs with other components, remember to release the `MediaController` when it is\nno longer needed, such as in the `onStop()` method of an `Activity` or\n`Fragment`. \n\n### Kotlin\n\n MediaController.releaseFuture(controllerFuture)\n\n### Java\n\n MediaController.releaseFuture(controllerFuture);\n\n\u003cbr /\u003e\n\nReleasing the controller will still deliver all pending commands sent to the\nsession and only unbind from the session service either once these commands have\nbeen handled or after a timeout period, whichever occurs first.\n\n`MediaBrowser`\n--------------\n\nA `MediaBrowser` builds on top of the capabilities offered by a\n`MediaController` to also enable browsing the media library offered by a media\napp's `MediaLibraryService`.\n\n### Create a `MediaBrowser`\n\n### Kotlin\n\n val browserFuture = MediaBrowser.Builder(context, sessionToken).buildAsync()\n browserFuture.addListener({\n // MediaBrowser is available here with browserFuture.get()\n }, MoreExecutors.directExecutor())\n\n### Java\n\n ListenableFuture\u003cMediaBrowser\u003e browserFuture =\n new MediaBrowser.Builder(context, sessionToken).buildAsync();\n browserFuture.addListener(() -\u003e {\n // MediaBrowser is available here with browserFuture.get()\n }, MoreExecutors.directExecutor());\n\n\u003cbr /\u003e\n\n### Use a `MediaBrowser`\n\nTo start browsing the media app's content library, first retrieve the root node\nwith `getLibraryRoot()`: \n\n### Kotlin\n\n // Get the library root to start browsing the library tree.\n val rootFuture = mediaBrowser.getLibraryRoot(/* params= */ null)\n rootFuture.addListener({\n // Root node MediaItem is available here with rootFuture.get().value\n }, MoreExecutors.directExecutor())\n\n### Java\n\n // Get the library root to start browsing the library tree.\n ListenableFuture\u003cLibraryResult\u003cMediaItem\u003e\u003e rootFuture =\n mediaBrowser.getLibraryRoot(/* params= */ null);\n rootFuture.addListener(() -\u003e {\n // Root node MediaItem is available here with rootFuture.get().value\n }, MoreExecutors.directExecutor());\n\n\u003cbr /\u003e\n\nYou can then navigate through the media library by retrieving the children of a\n`MediaItem` in the library with `getChildren()`. For example, to retrieve the\nchildren of the root node `MediaItem`: \n\n### Kotlin\n\n // Get the library root to start browsing the library tree.\n val childrenFuture = \n mediaBrowser.getChildren(rootMediaItem.mediaId, 0, Int.MAX_VALUE, null)\n childrenFuture.addListener({\n // List of children MediaItem nodes is available here with\n // childrenFuture.get().value\n }, MoreExecutors.directExecutor())\n\n### Java\n\n ListenableFuture\u003cLibraryResult\u003cImmutableList\u003cMediaItem\u003e\u003e\u003e childrenFuture =\n mediaBrowser.getChildren(rootMediaItem.mediaId, 0, Integer.MAX_VALUE, null);\n childrenFuture.addListener(() -\u003e {\n // List of children MediaItem nodes is available here with\n // childrenFuture.get().value\n }, MoreExecutors.directExecutor());\n\n\u003cbr /\u003e\n\nDisplay playback controls for another media app\n-----------------------------------------------\n\nWhen displaying UI controls with buttons for another media app, it's important\nto follow the declared [media button preferences](/media/media3/session/control-playback#commands) of that\napp.\n\nThe best way to resolve the preferences of the app and the constraints and\nrequirements of your UI, is to use `CommandButton.DisplayConstraints`. You can\ndefine limits and restrictions of your UI can do, and the\n[`resolve`](/reference/kotlin/androidx/media3/session/CommandButton.DisplayConstraints#resolve(java.util.List%3Candroidx.media3.session.CommandButton%3E,androidx.media3.common.Player)) method provides a definite list of buttons to\ndisplay with their icon, position and intended action."]]