You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MediaBrowserService中onLoadChildren方法如何获取媒体文件?

Hey there! Let's figure out how to properly load local music from MediaStore within your MediaBrowserService's onLoadChildren method—this is exactly where you should handle this logic, but we need to do it right to avoid blocking the main thread.

Key Background First

The onLoadChildren method is called whenever a connected MediaBrowser requests the list of media items under a specific parentMediaId (like the root of your media library, or an album/artist category). Since querying MediaStore is a time-consuming operation, we can't do it directly on the main thread—we need to offload it to a background thread and keep the result pending until we're done.

Step-by-Step Implementation

Here's a complete, working example that follows best practices:

@Override
public void onLoadChildren(
        @NonNull final String parentMediaId,
        @NonNull final Result<List<MediaBrowserCompat.MediaItem>> result) {

    // 1. Detach the result so we can process it off the main thread
    // This tells the system we'll send the result later
    result.detach();

    // 2. Use a background thread to query MediaStore
    // Note: AsyncTask is deprecated, but it's simple for demonstration—use ExecutorService or Coroutines in production
    new AsyncTask<Void, Void, List<MediaBrowserCompat.MediaItem>>() {
        @Override
        protected List<MediaBrowserCompat.MediaItem> doInBackground(Void... voids) {
            List<MediaBrowserCompat.MediaItem> mediaItems = new ArrayList<>();

            // Define which media fields we want to retrieve
            String[] projection = {
                    MediaStore.Audio.Media._ID,
                    MediaStore.Audio.Media.TITLE,
                    MediaStore.Audio.Media.ARTIST,
                    MediaStore.Audio.Media.ALBUM
            };

            // Optional: Filter out empty titles to avoid junk entries
            String selection = MediaStore.Audio.Media.TITLE + " != ?";
            String[] selectionArgs = {""};

            // Query the external storage for audio files
            Cursor cursor = getContentResolver().query(
                    MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
                    projection,
                    selection,
                    selectionArgs,
                    MediaStore.Audio.Media.TITLE + " ASC" // Sort alphabetically by title
            );

            if (cursor != null) {
                while (cursor.moveToNext()) {
                    // Extract data from the cursor
                    long mediaId = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID));
                    String title = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE));
                    String artist = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST));
                    String album = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM));

                    // Build a MediaDescription for the item
                    MediaDescriptionCompat description = new MediaDescriptionCompat.Builder()
                            .setMediaId(String.valueOf(mediaId))
                            .setTitle(title)
                            .setSubtitle(artist)
                            .setDescription(album)
                            .build();

                    // Create the MediaItem—mark as playable since these are music tracks
                    MediaBrowserCompat.MediaItem mediaItem = new MediaBrowserCompat.MediaItem(
                            description,
                            MediaBrowserCompat.MediaItem.FLAG_PLAYABLE
                    );

                    mediaItems.add(mediaItem);
                }
                cursor.close(); // Always close the cursor to avoid leaks!
            }

            return mediaItems;
        }

        @Override
        protected void onPostExecute(List<MediaBrowserCompat.MediaItem> mediaItems) {
            // 3. Send the result back on the main thread
            result.sendResult(mediaItems);
        }
    }.execute();
}

Critical Notes for Production

  • Permissions: Don't forget to request the necessary storage permissions:
    • For Android 10 (API 29) and below: READ_EXTERNAL_STORAGE
    • For Android 11+ (API 30+): READ_MEDIA_AUDIO
      You'll need to handle runtime permission requests before querying MediaStore, otherwise your cursor will return empty.
  • Replace AsyncTask: Since AsyncTask is deprecated, use ExecutorService or Kotlin Coroutines for background work. For example, with Executors:
    Executors.newSingleThreadExecutor().execute(() -> {
        // Do MediaStore query here
        List<MediaBrowserCompat.MediaItem> items = ...;
        new Handler(Looper.getMainLooper()).post(() -> result.sendResult(items));
    });
    
  • Category-Based Loading: If you want to organize music by albums or artists, use the parentMediaId to decide what to load. For example:
    • If parentMediaId is "root", load all albums
    • If parentMediaId is an album ID, load all tracks in that album (adjust your MediaStore query with a selection filter for the album ID)
  • Handle Media Updates: When local music files are added/removed, call notifyChildrenChanged(parentMediaId) to tell connected MediaBrowsers to refresh their list. You can use a ContentObserver to listen for changes in MediaStore.

内容的提问来源于stack exchange,提问作者Yeshia

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:17:55