在安卓系统中如何列出相册?

9

我正在开发一款简单的安卓音频播放器。我想要列出设备中的专辑。

我尝试了以下代码:

String where = new String();
where = MediaStore.Audio.Media.IS_MUSIC + "=1";
private Cursor managedCursor;
managedCursor = managedQuery(
        MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
        new String[] {  
            MediaStore.Audio.Media.TITLE,
            MediaStore.Audio.Media._ID,
            MediaStore.Audio.Media.ALBUM,       
            MediaStore.Audio.Media.ALBUM_ID,    
            MediaStore.Audio.Media.ARTIST,
            MediaStore.Audio.Media.ARTIST_ID
        },
        where,                                  
        null,                                       
        MediaStore.Audio.Media.DEFAULT_SORT_ORDER   
    );

  ListAdapter adapter = new AlbumListAdapter(
        this,                                   
        R.layout.albumlist_item,                
        managedCursor,                          
        new String[] {                          
            MediaStore.Audio.Media.ALBUM,       
            MediaStore.Audio.Media.ARTIST           
        },
        new int[] {                             
            R.id.text_album, 
            R.id.text_artist 
        }
    );
    setListAdapter(adapter);

但是这段代码列出了设备中所有的歌曲。
Android Media存储数据库的结构是什么?
请帮忙。
4个回答

10

你应该像这样查询相册

String[] projection = new String[] { Albums._ID, Albums.ALBUM, Albums.ARTIST, Albums.ALBUM_ART, Albums.NUMBER_OF_SONGS };
String selection = null;
String[] selectionArgs = null;
String sortOrder = Media.ALBUM + " ASC";
Cursor cursor = contentResolver.query(Albums.EXTERNAL_CONTENT_URI, projection, selection, selectionArgs, sortOrder);

http://developer.android.com/reference/android/provider/MediaStore.Audio.Albums.html

艺术家,播放列表和类型都可以使用正确的EXTERNAL_CONTENT_URI和相应的投影方式进行查询。

希望这有所帮助...


“ASC”是什么意思?它确实改变了我的媒体列表的顺序,但我不明白它在做什么。 - Zen
1
ASC命令按升序对结果集进行排序。在此示例中,它将按专辑名称的升序对列表进行排序。因此,按字母顺序A、B、C等进行排序...相反,DESC是降序排序。 - JeffG
非常好用。但是它会将以小写字母和大写字母开头的音乐文件分别排列。因此,在对它们进行排序之前,将所有媒体文件转换为小写字母 :) - Zen
你可以尝试使用以下代码进行排序:String sortOrder = "lower(" + Media.ALBUM + ") ASC"; 但我没有尝试过,也不确定它是否有效。如果我想要进行高级排序,我会将结果转换为对象,然后使用Comparator和Collection.sort进行排序。希望这能帮到你。 - JeffG
1
@JeffG 它会显示专辑列表,但如果我们要获取唯一值,它也会显示重复值,因此我们必须对专辑使用DISTINCT关键字,但是我们无法选择多个列,即使我们对专辑使用distinct关键字并使用其他列,它仍然会迭代重复数据。我们如何才能获得唯一的数据? - Akshay Mukadam

4
请使用以下简化代码获取相册列表。
public ArrayList<AlbumModel> getListOfAlbums(Context context) {

            String where = null;

            final Uri uri = MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI;
            final String _id = MediaStore.Audio.Albums._ID;
            final String album_name = MediaStore.Audio.Albums.ALBUM;
            final String artist = MediaStore.Audio.Albums.ARTIST;
            final String albumart = MediaStore.Audio.Albums.ALBUM_ART;
            final String tracks = MediaStore.Audio.Albums.NUMBER_OF_SONGS;

            final String[] columns = { _id, album_name, artist, albumart, tracks };
            Cursor cursor = context.getContentResolver().query(uri, columns, where,
                    null, null);

            ArrayList<AlbumModel> list = new ArrayList<AlbumModel>();

            // add playlsit to list

            if (cursor.moveToFirst()) {

                do {

                    AlbumModel albumData = new AlbumModel();

                    albumData
                            .setAlbumID(cursor.getLong(cursor.getColumnIndex(_id)));

                    albumData.setAlbumName(cursor.getString(cursor
                            .getColumnIndex(album_name)));

                    albumData.setALbumArtist(cursor.getString(cursor
                            .getColumnIndex(artist)));

                    albumData.setAlbumArt(cursor.getString(cursor
                            .getColumnIndex(albumart)));

                    albumData.setTracks(cursor.getString(cursor
                            .getColumnIndex(tracks)));

                    list.add(albumData);

                } while (cursor.moveToNext());
            }

            cursor.close();

            return list;
        }

2
public class Album {

private long id;
private String albumName;
private String artistName;
private int nr_of_songs;
private Bitmap albumImg;

public Album(long id, String albumName, String artistName, Bitmap albumImg,  int nr_of_songs) {
    this.albumImg = albumImg;
    this.id = id;
    this.albumName = albumName;
    this.artistName = artistName;
    this.nr_of_songs = nr_of_songs;
}

public void setId(long id) {
    this.id = id;
}
public void setAlbumName(String albumName) {
    this.albumName = albumName;
}
public void setArtistName(String artistName) {
    this.artistName = artistName;
}
public void setAlbumImg(Bitmap albumImg) {
    this.albumImg = albumImg;
}
public void setNr_of_songs(int nr_of_songs) {
    this.nr_of_songs = nr_of_songs;
}

public long getID(){
    return id;
}
public String getAlbumName(){
    return albumName;
}
public String getArtistName() {
    return artistName;
}
public Bitmap getAlbumImg() {
    return albumImg;
}
public int getNr_of_songs() {
    return nr_of_songs;
}

}


 public void getAlbumsLists(){
    String where = null;

    final Uri uri = MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI;
    final String _id = MediaStore.Audio.Albums._ID;
    final String album_name = MediaStore.Audio.Albums.ALBUM;
    final String artist = MediaStore.Audio.Albums.ARTIST;
    final String albumart = MediaStore.Audio.Albums.ALBUM_ART;
    final String tracks = MediaStore.Audio.Albums.NUMBER_OF_SONGS;

    final String[] columns = { _id, album_name, artist, albumart, tracks };
    Cursor cursor = context.getContentResolver().query(uri, columns, where, null, null);

    if(cursor!=null && cursor.moveToFirst()){

        do {

            long id = cursor.getLong(cursor.getColumnIndex(_id));
            String name = cursor.getString(cursor.getColumnIndex(album_name));
            String artist2 = cursor.getString(cursor.getColumnIndex(artist));
            String artPath = cursor.getString(cursor.getColumnIndex(albumart));
            Bitmap art = BitmapFactory.decodeFile(artPath);
            int nr =Integer.parseInt(cursor.getString(cursor.getColumnIndex(tracks)));

            albumList.add(new Album(id, name, artist2, art, nr));

        } while (cursor.moveToNext());
    }

    cursor.close();
}

2

这是原始答案

我通过检查它们是否已经添加到我的映射中来对唯一的专辑进行排序。

public Map<String, String> getAlbumList(Context c) {
    //setup map and cursor
    Map<String, String> result = new HashMap<String, String>();
    String selection = MediaStore.Audio.Media.IS_MUSIC + " !=0";
    final Cursor mCursor = c.getContentResolver().query(
            MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
            new String[] {MediaStore.Audio.Media.ALBUM,
                    MediaStore.Audio.Media.ARTIST,
                    MediaStore.Audio.Media.ALBUM_ID,}, selection, null,
                   "LOWER ("+MediaStore.Audio.Media.ALBUM + ") ASC");

    int count = mCursor.getCount();


    String[] mArtist = new String[count];
    String[] mAlbum = new String[count];
    String[] AlbumID = new String[count];

    int i = 0;
    int j = 0;
    if (mCursor.moveToFirst()) {

        do {
            mAlbum[i] = mCursor
                    .getString(mCursor
                            .getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM));
            mArtist[i] = mCursor.getString(mCursor
                    .getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST));

            AlbumID[i] = Long.toString(mCursor
                    .getLong(mCursor
                            .getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM_ID)));

                                    //checking for same previous value
            if(result.containsValue(mAlbum[i])){

            }else{
            result.put("artist" + j, mArtist[i]);
            result.put("album" + j, mAlbum[i]);
            result.put("AlbumID" + j, AlbumID[i]);
            j = j + 1;
            }
            i = i + 1;

        } while (mCursor.moveToNext());
    }

    result.put("count", Integer.toString(j));
    mCursor.close();
    return result;
}
}

也许这并不是唯一的专辑排序方法,但是它可以完全按照预期工作,而无需使用 sqlite 进行操作,虽然外观可能不够美观。
我在这里传递了一个上下文,因为我在 fragment 中使用了一个带有自定义适配器的 listview,如果没有活动上下文 getContentResolver() 就无法工作。
附加到原始答案中:
mArt、mData、mAlbums 和 mArtists 都是 ArrayLists。
private void getList(View view){
    mArt.clear();
    mAlbums.clear();
    mArtists.clear();

    String[] projection = {"DISTINCT " + MediaStore.Audio.Media.ALBUM_ID,
            MediaStore.Audio.Media.ALBUM,
            MediaStore.Audio.Media.ARTIST

    } ;

    String[] projection2 = {"Distinct " + MediaStore.Audio.Albums.ALBUM,
    MediaStore.Audio.Albums.NUMBER_OF_SONGS};

    Cursor mCursor =  getActivity().getApplicationContext().getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, projection, "0==0 ) GROUP BY (" + MediaStore.Audio.Media.ALBUM_ID, null, MediaStore.Audio.Media.ALBUM + " COLLATE NOCASE ASC");
    Cursor mCursor2 = getActivity().getApplicationContext().getContentResolver().query(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, projection2, null, null, MediaStore.Audio.Albums.ALBUM + " COLLATE NOCASE ASC");

    if(mCursor != null && mCursor.getCount() > 0 && mCursor2 != null && mCursor2.getCount() > 0){
        CursorJoiner joiner = new CursorJoiner(mCursor, new String[]{MediaStore.Audio.Media.ALBUM},mCursor2, new String[]{MediaStore.Audio.Albums.ALBUM});

        for (CursorJoiner.Result joinerResult : joiner) {
            switch (joinerResult) {
                case LEFT:
                    break;
                case RIGHT:
                    break;
                case BOTH:
                    String songs_s = "Song";
                    int tracks = mCursor2.getInt(mCursor2.getColumnIndex(MediaStore.Audio.Albums.NUMBER_OF_SONGS));
                    if (tracks > 1) {
                        songs_s = "Songs";
                    }
                    mArtists.add(tracks + " " + songs_s + " By " + mCursor.getString(mCursor.getColumnIndex(MediaStore.Audio.Media.ARTIST)));
                    mAlbums.add(mCursor2.getString(mCursor2.getColumnIndex(MediaStore.Audio.Albums.ALBUM)));
                    mArt.add(ContentUris.withAppendedId(Uri.parse("content://media/external/audio/albumart"), mCursor.getInt(mCursor.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID))));

            }
        }
    }
    mCursor.close();
    mCursor2.close();
}

选择语句中的GROUP BY子句确保唯一的专辑,因为专辑封面是按照专辑ID存储的,以下是该行:

mArt.add(ContentUris.withAppendedId(Uri.parse("content://media/external/audio/albumart"), mCursor.getInt(mCursor.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID))));

确保专辑封面和专辑在同一位置...

我在这里使用游标连接器,以便可以获取艺术家、专辑和专辑中歌曲的数量...这只能从两个单独的查询中返回...


@vince 是的,它可以... 但是在我写完这个答案后,我发现了一种更简单的方法... 我会编辑答案以反映这一点... - me_
第二个代码块返回三个ArrayList:mArt包含专辑封面URI,mAlbum包含专辑名称,mArtist包含艺术家名称和字符串形式的专辑中歌曲数量,例如“x首歌曲由艺术家演唱”。您只需要知道任何一个元素的位置,其他所有元素都在其各自列表的相同位置。 - me_
@me_ 我正在使用一个模型类 Song 来存储所有信息。我可以使用它来代替 ArrayList 吗?例如:song.setArtist(tracks + " " + songs_s + " By " + mCursor.getString(mCursor.getColumnIndex(MediaStore.Audio.Media.ARTIST))); - Vince VD
@artman 没有啊...我只是在Android 10.0 (Q),API 29,修订版3上测试了这段代码。 - me_
@me_ 这很奇怪,因为我在Pixel上遇到了稳定的崩溃。 - artman
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接