从Cursor覆盖或更新Android播放列表数据库

时间:2016-09-20 19:54:18

标签: java android sqlite android-studio playlist

我正在编写一个小应用程序来检索Android创建的播放列表中的所有项目,并能够按特定顺序对列表进行排序。我想要做的是这种实际上保存回数据库,或更新播放列表文件。作为Android开发的相对新手,我不确定这是什么方法。

这是我的代码:

import android.content.ContentResolver;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.provider.MediaStore;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Spinner;

import java.util.List;

public class PlaylistSongActivity extends AppCompatActivity {
    final String SONG_ID_KEY  = MediaStore.Audio.AudioColumns._ID;
    final String SONG_ARTIST_KEY  = MediaStore.Audio.AudioColumns.ARTIST;
    final String SONG_ALBUM_KEY = MediaStore.Audio.AudioColumns.ALBUM;
    final String SONG_TITLE_KEY  = MediaStore.Audio.AudioColumns.TITLE;
    final String SONG_TRACK_NO_KEY = MediaStore.Audio.AudioColumns.TRACK;
    final String CASE_INSENTIVE = " COLLATE NOCASE ";
    final String[] PLAYLIST_QUERY_COLUMNS = {SONG_ID_KEY, SONG_ARTIST_KEY, SONG_TITLE_KEY, SONG_ALBUM_KEY, SONG_TRACK_NO_KEY};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_playlist);
        // Spinner values
        final Spinner playlistSettingsDropdown = (Spinner) findViewById(R.id.playlistSettingsDropdown);
        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this, R.array.playlist_settings_array, android.R.layout.simple_spinner_item);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        playlistSettingsDropdown.setAdapter(adapter);
        playlistSettingsDropdown.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
                sortGrid(pos);
            }

            public void setId(int pos) {
                playlistSettingsDropdown.setSelection(pos);
            }

            public void onNothingSelected(AdapterView<?> parent) {
                // Another interface callback
            }
        });

        // Song grid
        ListView playlistSongsView = getSongGrid();
        final Cursor playlistSongs = createPlaylistCursor(null);
        PlaylistSongCursor playlistSongsAdapter = new PlaylistSongCursor(playlistSongsView.getContext(), playlistSongs);
        playlistSongsView.setAdapter((playlistSongsAdapter));
    }

    public void sortGrid(int sortType) {
        ListView songGrid = getSongGrid();
        PlaylistSongCursor songGridAdapter = (PlaylistSongCursor) songGrid.getAdapter();
        String sort = SONG_ARTIST_KEY + CASE_INSENTIVE + " ASC," +
                SONG_ALBUM_KEY + CASE_INSENTIVE + " ASC," +
                SONG_TRACK_NO_KEY + " ASC";
        switch (sortType) {
            case 1:
                sort = SONG_ARTIST_KEY + CASE_INSENTIVE + " DESC," +
                        SONG_ALBUM_KEY + CASE_INSENTIVE + " DESC," +
                        SONG_TRACK_NO_KEY + " DESC";
        }
        songGridAdapter.changeCursor(createPlaylistCursor(sort));
    }

    public ListView getSongGrid() {
        return (ListView) findViewById((R.id.playlistItems));
    }

    public Uri getPlaylistUri() {
        int playlistId = getIntent().getExtras().getInt("playlistId");
        return MediaStore.Audio.Playlists.Members.getContentUri("external", playlistId);
    }

    public Cursor createPlaylistCursor(String sort) {
        return getContentResolver().query(getPlaylistUri(), null, null, null, sort);
    }
}

所以我从我传递的意图中获取列表的ID,从MediaStore包中获取其URI,然后使用URI从查询中使用ContentProvider获取Cursor。这一切都有效,播放列表的歌曲显示得很好,我的排序也很有效(尽管我欢迎对我正在做的事情进行批评)。问题是我如何使用光标保存回数据库,因此它会持续存在于其他音乐应用程序中? (BlackPlayer具有此功能及其按艺术家排序 - 专辑选项)

我在考虑几种方法,但我并不完全确定如何执行它们:

  • 使用ContentValues执行某些操作(从中检索 DatabaseUtils.cursorRowToContentValues
  • 以某种方式使用getWritableDatabase ...不确定如何检索数据库本身
  • 覆盖File,但因为它是URISQLite文件,我不确定如何保存File这样的内容。 ..它必须采用特殊格式吗?

有没有人有任何见解?

更新

我开始沿着使用bulkInsert的路线前进,但似乎它没有将ContentValues[]插入我的数据库......这肯定会删除我的行,而我的retVal包含要插入的项目数量,它不会插入...

    myButton.setOnClickListener(new AdapterView.OnClickListener() {
        public void onClick(View view) {
            ListView songGrid = getSongGrid();
            PlaylistSongCursor songGridAdapter = (PlaylistSongCursor) songGrid.getAdapter();
            Cursor myCursor = songGridAdapter.getCursor();
            ContentValues[] retVal = new ContentValues[myCursor.getCount()];
            ContentValues map;
            int i = 0;
            if(myCursor.moveToFirst()) {
                do {
                    map = new ContentValues();
                    DatabaseUtils.cursorRowToContentValues(myCursor, map);
                    retVal[i++] = map;
                } while(myCursor.moveToNext());
            }
            // Empties db
            getContentResolver().delete(getPlaylistUri(), null, null);
            // Logs 2 (as that's how many items are in my list)
            Log.d("BLA", String.valueOf(retVal.length));
            final int retInt = getContentResolver().bulkInsert(getPlaylistUri(), retVal);
            // Logs 0
            Log.d("DONE", String.valueOf(retInt));
        }
    });

2 个答案:

答案 0 :(得分:1)

查看ContentProvider的官方文档。基本上ContentProvider隐藏了数据库,因此您可以使用URI(如果需要,可以ContentValues)与之通信,但不能直接与数据库进行通信。

//Create empty values
ContentValues values= new ContentValues();

//put all you want to update
values.put(MediaStore.Audio.Playlists.Members.DEFAULT_SORT_ORDER, sort);

//call update method on ContentResolver
int rows = getContentResolver().update(
    getPlaylistUri(), //uri to modify
    values, //new values for 
    MediaStore.Audio.Playlists.Members.PLAYLIST_ID + "=?", //selection clause 
    new String[] {String.valueOf(playlistId)} //selection args
);

如果您不指定排序参数,我假设query应根据此列对您的播放列表进行排序

return getContentResolver().query(getPlaylistUri(), 
                      PLAYLIST_QUERY_COLUMNS, null, null, null);

根据ContentResolver doc:

  

字符串:如何对行进行排序,格式为SQL ORDER BY子句   (不包括ORDER BY本身)。传递null将使用默认值   排序顺序,可能是无序的。

还有另一个选项 - 创建自己的数据库,它将使用order by子句存储播放列表的ID,您可以自己维护(即您的项目中有关于播放列表或排序等的更复杂的逻辑)。 )。

修改

您确定myCursor(映射到retVal)是否包含插入所需的所有数据?您应确保所有必需的列在您要根据URI 插入的每一行的内容值中保留。您检索了(MediaStore.Audio.Playlists.Members)URI,其中包含光标所需的列。但是,您选择的列来自继承的MediaStore.Audio.AudioColumns。它适用于query,因为ContentProvider可能只是加入一些音频表来获取这些。但是现在您想要将数据(根据URI)插入到MediaStore.Audio.Playlists.Members中,但是您没有指定任何列,因为您所拥有的只是来自链接表(AudioColumns)的数据。

  • query - 选择您要从提供的列中选择的内容
  • update - 根据选择
  • 为行添加要更新的值
  • insert - 为表格提供所有必需的值

最后一件事,遗憾的是你不能强迫第三方提供者尊重DEFAULT_SORT_ORDER。您可以尝试清除缓存,但我怀疑它会有所帮助。

答案 1 :(得分:0)

qbeck获得了大量帮助后,我能够解决这个问题。我错过了一些重要的事情......为了保存回到播放列表The specified listener is invoked in the same manner as other operator functions, being passed the current datum d and index i, with the this context as the current DOM element. ,我必须确保它使用了与其架构相同的列...查看{{1} }属性,我可以收集表格的实际字段是什么...... Android Studio以粗体显示这些键,但现在回头看看,我认为这是{什么{ {3}}告诉我。

我使用这些信息来确定我需要更新this page值,所以我首先开始了Uri的路线,但对于每一行,这对于大型列表需要相当长的时间,我达到某种Cursor undefined错误。然后我尝试删除数据库中的所有行并执行PLAY_ORDER,这要快得多并且做了我需要它做的事情...现在我的列表在其他音乐应用程序中以此排序顺序出现。

MediaStore.Audio.Playlists.Members.*