Android MediaBrowserService音频播放器定制:添加歌曲与网络专辑封面
Let's tackle your two issues one by one—they're both common hurdles when building a media player with Android's Media framework, so I'll break down practical steps for each:
The key here is using Android's MediaController and MediaSession to communicate between your Activity and MediaBrowserService. Here's how to implement both "Add and Play" and "Add to Queue End" actions:
Step 1: Define custom actions in your MediaBrowserService
First, add constants for your custom commands in your service class so your Activity can reference them:
public class YourMediaService extends MediaBrowserServiceCompat { public static final String ACTION_ADD_AND_PLAY = "com.your.app.package.ACTION_ADD_AND_PLAY"; public static final String ACTION_ADD_TO_QUEUE_END = "com.your.app.package.ACTION_ADD_TO_QUEUE_END"; public static final String EXTRA_MEDIA_ITEM = "com.your.app.package.EXTRA_MEDIA_ITEM"; // ... existing service code ... }
Step 2: Handle custom commands in the MediaSession Callback
Update your MediaSession.Callback to process these commands and modify the playback queue:
mediaSession.setCallback(new MediaSessionCompat.Callback() { // ... existing callbacks (onPlay, onPause, etc.) ... @Override public void onCommand(String command, Bundle extras, ResultReceiver cb) { super.onCommand(command, extras, cb); if (extras == null || !extras.containsKey(EXTRA_MEDIA_ITEM)) { sendResult(cb, 0); return; } MediaItemCompat mediaItem = extras.getParcelable(EXTRA_MEDIA_ITEM); if (mediaItem == null) { sendResult(cb, 0); return; } switch (command) { case ACTION_ADD_AND_PLAY: addAndPlayItem(mediaItem); sendResult(cb, 1); break; case ACTION_ADD_TO_QUEUE_END: addItemToQueueEnd(mediaItem); sendResult(cb, 1); break; default: sendResult(cb, 0); } } private void sendResult(ResultReceiver cb, int resultCode) { if (cb != null) { cb.sendResult(resultCode, null); } } private void addAndPlayItem(MediaItemCompat item) { List<MediaSessionCompat.QueueItem> currentQueue = mediaSession.getQueue(); List<MediaSessionCompat.QueueItem> newQueue = new ArrayList<>(); if (currentQueue != null) { newQueue.addAll(currentQueue); } newQueue.add(new MediaSessionCompat.QueueItem(item.getDescription(), newQueue.size())); mediaSession.setQueue(newQueue); // Switch to the new item and play mediaSession.getController().getTransportControls().skipToQueueItem(newQueue.size() - 1); } private void addItemToQueueEnd(MediaItemCompat item) { List<MediaSessionCompat.QueueItem> currentQueue = mediaSession.getQueue(); List<MediaSessionCompat.QueueItem> newQueue = new ArrayList<>(); if (currentQueue != null) { newQueue.addAll(currentQueue); } newQueue.add(new MediaSessionCompat.QueueItem(item.getDescription(), newQueue.size())); mediaSession.setQueue(newQueue); } });
Step 3: Trigger actions from your other Activity
In your search (or other) Activity, use MediaController to send the commands to the service. Make sure you've already connected to the MediaBrowser first:
// Get the MediaController (you can get this via MediaBrowser's connection callback) MediaControllerCompat mediaController = MediaControllerCompat.getMediaController(this); // Example: "Add and Play" button click buttonAddAndPlay.setOnClickListener(v -> { Bundle extras = new Bundle(); extras.putParcelable(YourMediaService.EXTRA_MEDIA_ITEM, yourTargetMediaItem); mediaController.sendCommand(YourMediaService.ACTION_ADD_AND_PLAY, extras, new ResultReceiver(new Handler(Looper.getMainLooper())) { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { super.onReceiveResult(resultCode, resultData); Toast.makeText(SearchActivity.this, resultCode == 1 ? "Added and playing" : "Failed to add", Toast.LENGTH_SHORT).show(); } }); }); // Example: "Add to Queue End" button click buttonAddToQueue.setOnClickListener(v -> { Bundle extras = new Bundle(); extras.putParcelable(YourMediaService.EXTRA_MEDIA_ITEM, yourTargetMediaItem); mediaController.sendCommand(YourMediaService.ACTION_ADD_TO_QUEUE_END, extras, new ResultReceiver(new Handler(Looper.getMainLooper())) { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { super.onReceiveResult(resultCode, resultData); Toast.makeText(SearchActivity.this, resultCode == 1 ? "Added to queue" : "Failed to add", Toast.LENGTH_SHORT).show(); } }); });
The default Google example uses local drawables, but switching to remote images just requires adjusting how you set the album art URI, plus using an image loader library (like Glide) to handle network loading and caching.
Step 1: Fetch album art URL from Last FM API
First, make sure you're requesting the album info from Last FM with your API key. A sample API request looks like this:
https://ws.audioscrobbler.com/2.0/?method=album.getinfo&api_key=YOUR_LASTFM_API_KEY&artist=ARTIST_NAME&album=ALBUM_NAME&format=json
Parse the JSON response to get the album art URL—look for the image array, and pick the size you need (e.g., large or extralarge).
Step 2: Update MusicLibrary to use remote URIs
Modify your MusicLibrary class to set the remote URL as the icon URI in your MediaDescription:
public class MusicLibrary { // ... existing code ... public static MediaDescriptionCompat getMediaDescription(Context context, String mediaId) { // Fetch your song data (artist, album, etc.) Song song = getSongById(mediaId); // Get the album art URL from your Last FM response String albumArtUrl = song.getAlbumArtUrl(); Uri albumArtUri = Uri.parse(albumArtUrl != null ? albumArtUrl : "android.resource://" + context.getPackageName() + "/" + R.drawable.default_cover); return new MediaDescriptionCompat.Builder() .setMediaId(mediaId) .setTitle(song.getTitle()) .setSubtitle(song.getArtist()) .setIconUri(albumArtUri) .build(); } }
Step 3: Load remote images with Glide in your UI
Android's default image loading won't handle remote URLs reliably, so use Glide to load the album art in your RecyclerView adapters and playback UI:
// In your RecyclerView.ViewHolder bind method Glide.with(itemView.getContext()) .load(mediaItem.getDescription().getIconUri()) .placeholder(R.drawable.default_cover) // Show while loading .error(R.drawable.default_cover) // Show if load fails .centerCrop() .into(albumArtImageView);
Step 4: Add required permissions
Don't forget to add internet permission to your AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET" />
内容的提问来源于stack exchange,提问作者Sunil Meena

