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());
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());
// 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());
[null,null,["最后更新时间 (UTC):2025-08-21。"],[],[],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."]]