【问题标题】:How to create a new Playlist using ContentResolver如何使用 ContentResolver 创建新的播放列表
【发布时间】:2012-06-10 13:58:38
【问题描述】:

我正在尝试使用 Android 的 ContentResolver 创建一个新的 Playlist,它将添加到音乐播放器的播放列表中,但是当代码运行时,插入到播放列表中返回 null(对于 Uri)当我检查音乐播放器的播放列表时,我的新 Playlist 条目不存在。我怀疑insert() 返回 null 的原因是因为我没有正确创建播放列表。鉴于我的代码不起作用,有人可以澄清如何动态创建新的播放列表。 (在我的搜索中,我找到了几种查询播放列表的方法,但实际上并没有创建新的方法)

这是我的代码...

    ContentResolver resolver = getActivity().getContentResolver();

    Uri playlists = MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI;

    Log.d(A.TAG, "Checking for existing playlist for " + chart.getName());
    Cursor c = resolver.query(playlists, new String[] {"*"}, null, null, null);
    long playlistId = 0;
    c.moveToFirst();
    do {
        String plname = c.getString(c.getColumnIndex(MediaStore.Audio.Playlists.NAME));
        if (plname.equalsIgnoreCase(chart.getName())) {
            playlistId = c.getLong(c.getColumnIndex(MediaStore.Audio.Playlists._ID));
            break;
        }
    } while (c.moveToNext());
    c.close();

    if (playlistId!=0) {
        Uri deleteUri = ContentUris.withAppendedId(playlists, playlistId);
        Log.d(A.TAG, "REMOVING Existing Playlist: " + playlistId);

        // delete the playlist
        resolver.delete(deleteUri, null, null);
    }

    Log.d(A.TAG, "CREATING PLAYLIST: " + chart.getName());
    ContentValues v = new ContentValues();
    v.put(MediaStore.Audio.Playlists.NAME, chart.getName());
    v.put(MediaStore.Audio.Playlists.DATE_MODIFIED, System.currentTimeMillis());
    Uri newpl = resolver.insert(playlists, v);
    Log.d(A.TAG, "Added PlayLIst: " + newpl);

    Uri insUri = Uri.withAppendedPath(newpl, MediaStore.Audio.Playlists.Members.CONTENT_DIRECTORY);

    int order = 1;
    Log.d(A.TAG, "Playlist Members Url: " + insUri);
    c = getContentManager().queryWhere(getActivity(), Song.class, Song.Fields.LIBRARYID + " != 0 and " + Song.Fields.CHARTID + " = " + chart.getId(), (String[])null);
    if (c.moveToFirst()) {
        Log.d(A.TAG, "Adding Songs to PlayList **");
        do {
            long id = c.getLong(c.getColumnIndex(Song.Fields.LIBRARYID));
            ContentValues cv = new ContentValues();
            cv.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, order++);
            cv.put(MediaStore.Audio.Playlists.Members.AUDIO_ID, id);
            Uri u = resolver.insert(insUri, cv);
            Log.d(A.TAG, "Added Playlist Item: " + u + " for AUDIO_ID " + id);
        } while (c.moveToNext());
    }
    c.close();

更新:部分解决**

上述代码确实在4.0.3 上正确添加了一个新播放列表,但在2.3 上却没有。 4.0.3 的唯一问题区域是我需要确保在播放列表中设置了DATE_MODIFIED,并且在播放列表项中设置了PLAY_ORDER

我仍然不知道为什么它不会在 2.x 上创建播放列表,所以如果有人对此有任何想法,我想知道。

【问题讨论】:

    标签: android android-contentprovider android-music-player


    【解决方案1】:

    这是我在自定义构建的 AsyncTask 中使用的代码,它适用于 2.3、3.1 和 4.03:

                ContentValues mInserts = new ContentValues();
                mInserts.put(MediaStore.Audio.Playlists.NAME, mPrefs.getString(AM.MEDIASTORECHANGE_NEWPLAYLISTNAME, "New Playlist"));
                mInserts.put(MediaStore.Audio.Playlists.DATE_ADDED, System.currentTimeMillis());
                mInserts.put(MediaStore.Audio.Playlists.DATE_MODIFIED, System.currentTimeMillis());
                mUri = mCR.insert(MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI, mInserts);
                if (mUri != null) {
                    mPlaylistId = -1;
                    mResult = FM.SUCCESS;
                    c = mCR.query(mUri, PROJECTION_PLAYLIST, null, null, null);
                    if (c != null) {
                        // Save the newly created ID so it can be selected.  Names are allowed to be duplicated,
                        // but IDs can never be.
                        mPlaylistId = c.getInt(c.getColumnIndex(MediaStore.Audio.Playlists._ID));
                        c.close();
                    }
                    if (DBG.AUDIO) {
                        Log.d(TAG, "PLAYLIST_ADD - mPlaylistId: " + mPlaylistId 
                                + "  mSelectString: " + mSelectString + "  mUri: "+ mUri.toString());
                    }
    
                }
    
    public static final String[] PROJECTION_PLAYLIST = new String[] {
        MediaStore.Audio.Playlists._ID,
        MediaStore.Audio.Playlists.NAME,
        MediaStore.Audio.Playlists.DATA
    };
    

    要获得正确的 Uri 以添加播放列表成员,您需要 Id。要将歌曲添加到播放列表,您还需要知道播放列表当前状态下 PLAYORDER 的当前高水位。否则,MediaStore ContentResolver 会因为您尝试插入具有相同播放顺序的播放列表成员而作呕。因此,您需要先查询 Playlist Uri 以获得最高的 PLAYORDER 值,并将其用作 ContentValues 插入的起点。

    我只尝试一次插入一个播放列表成员,但理论上您可能可以进行批量插入。下面的代码设置为将来转换为批量插入,但目前一次只插入一个。它采用 MediaStore.Audio.Media 歌曲的光标并将它们插入到已存储在 SharedPreferences 中的播放列表 Id 中。

        private void addSongsInCursorToPlaylist(Cursor c) {
        int mIdCol;
        int mCount;
        int mPercent = 0;
        ContentResolver mCR = mContext.getContentResolver();
        ContentProviderClient mCRC = null;
        try {
            mCount = c.getCount();
            mIdCol = c.getColumnIndex(MediaStore.Audio.Media._ID);
            ContentValues[] mInsertList = new ContentValues[1];
            mInsertList[0] = new ContentValues();
            int mPlaylistId  = mPrefs.getInt(AM.PLAYLIST_NOWPLAYING_ID, AM.PLAYLIST_ID_DEFAULT);
            Uri mUri = MediaStore.Audio.Playlists.Members.getContentUri("external", mPlaylistId);
            Cursor c2 = mCR.query(mUri, 
                    PROJECTION_PLAYLISTMEMBERS_PLAYORDER, null, null, MediaStore.Audio.Playlists.Members.PLAY_ORDER + " DESC ");
            int mPlayOrder = 1;
            if (c2 != null) {
                if (c2.moveToFirst()) {
                    mPlayOrder = (c2.getInt(c2.getColumnIndex(MediaStore.Audio.Playlists.Members.PLAY_ORDER))) + 1;
                }
                c2.close();
            }
            mCRC = mCR.acquireContentProviderClient(mUri);
            if (DBG.AUDIO) {
                Log.d(TAG, "addSongsInCursorToPlaylist -Content Uri: " + mUri.toString() 
                        + "  PlaylistID: " + mPlaylistId + " mPlayOrder: " + mPlayOrder);
            }
            for (int i=0; i< mCount; i++) {
                if (c.moveToPosition(i)) {
                    // Don't pollute with progress messages..has to be at least 1% increments
                    int mTemp = (i * 100) / (mCount );
                    if (mTemp > mPercent) {
                        mPercent = mTemp;
                        publishProgress(mPercent);
                    }
                    mInsertList[0].put(MediaStore.Audio.Playlists.Members.AUDIO_ID, c.getLong(mIdCol));
                    mInsertList[0].put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, mPlayOrder++);
                    mCR.insert(mUri, mInsertList[0]);
                    if (DBG.AUDIO) {
                        Log.d(TAG, "addSongsInCursorToPlaylist -Adding AudioID: " + c.getLong(mIdCol) + " to Uri: " + mUri.toString()  );
                    }
                }
                mCRC.release();
            }
        } catch (Throwable t) {
            t.printStackTrace();
        }
    
    }
        // Projection to get high water mark of PLAY_ORDER in a particular playlist
    public static final String[] PROJECTION_PLAYLISTMEMBERS_PLAYORDER = new String[] {
        MediaStore.Audio.Playlists.Members._ID,
        MediaStore.Audio.Playlists.Members.PLAY_ORDER
    };
    // Projection to get the list of song IDs to be added to a playlist
    public static final String[] PROJECTION_SONGS_ADDTOPLAYLIST = new String[] {
        MediaStore.Audio.Media._ID,
    };
    

    【讨论】:

    • 感谢@MarkG。我最终确实得到了这个工作。看来它无法在我的 2.x 设备上运行的原因是它正在运行 miui。我猜 miui 没有使用标准的播放列表内容提供商。当我用 cyanogen mod 重新刷新设备时,一切正常。
    • 应用程序在这一行崩溃 mPlaylistId = c.getInt(c.getColumnIndex(MediaStore.Audio.Playlists._ID));
    • 没关系我根据自己的需要更改它,只是为了确认 Cursor c = mCR.query(mUri, PROJECTION_PLAYLIST, null, null, MediaStore.Audio.Playlists.DATE_MODIFIED); if (c != null) { c.moveToLast();
    • ..只是为了确认一下,修改日期将按升序排序,对吗?因此新创建的播放列表将添加到最后,对吗?因此移到最后可以解决问题?
    猜你喜欢
    • 2016-09-07
    • 2012-08-14
    • 2017-11-07
    • 2020-09-30
    • 1970-01-01
    • 2015-10-01
    • 2022-01-24
    • 2023-03-31
    • 2018-01-15
    相关资源
    最近更新 更多