When I launch my application after upgrading from android 7 to 8.1 I noticed that it lost a lot of responsiveness.
When I'm trying to get songs from device memory I get a lot of errors like:
E/SEC_DRM_PLUGIN_Omafl: OmaPlugin::onOpenDecryptSession(fd)::Drm2IsDrmFileByExtFd::file is NOT DRM by extension
That works much slower than on the Android 7.
Code:
public ArrayList<Song> getSongList() {
MediaMetadataRetriever metaRetriver = new MediaMetadataRetriever();
String selection = MediaStore.Audio.Media.IS_MUSIC + " != 0";
ArrayList<Song> songList = new ArrayList<>();
ContentResolver musicResolver = context.getContentResolver();
Uri musicUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
Cursor musicCursor = musicResolver.query(musicUri, null, selection, null, null);
if (musicCursor != null && musicCursor.moveToFirst()) {
int titleColumn = musicCursor.getColumnIndex(MediaStore.Audio.Media.TITLE);
int idColumn = musicCursor.getColumnIndex(MediaStore.Audio.Media._ID);
int artistColumn = musicCursor.getColumnIndex(MediaStore.Audio.Media.ARTIST);
int durationColumn = musicCursor.getColumnIndex(MediaStore.Audio.Media.DURATION);
int column_index = musicCursor.getColumnIndex(MediaStore.Audio.Media.DATA);
do {
long id = musicCursor.getLong(idColumn);
String path = musicCursor.getString(column_index);
String title = musicCursor.getString(titleColumn);
String artist = musicCursor.getString(artistColumn);
String duration = musicCursor.getString(durationColumn);
try {
metaRetriver.setDataSource(path);
songList.add(new Song(id, title, artist, path, duration));
}catch (Exception exc){}
} while (musicCursor.moveToNext());
}
return songList;
}
I had to delete the one line of code that was causing the error when trying to get every single song from memory:
mediaMetadataRetriver.setDataSource(pathOfSong);
Hope it will help you.
Related
I am new to android. I am implementing music player using service. Here is the code in which error is focused. Can anyone help me out to solve this error?
public void getSong() {
ContentResolver contentResolver = getContentResolver();
Uri musicUri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
Cursor cursor = contentResolver.query(musicUri, null, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
do {
long thisId = cursor.getLong(cursor.getColumnIndex(MediaStore.Audio.Media._ID));
String thisTitle = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.TITLE));
String thisArtist = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST));
int albumId = cursor.getColumnIndex(android.provider.MediaStore.Audio.Albums.ALBUM_ART);
String thisArt = cursor.getString(albumId);
musicArrayList.add(new Music(thisId, thisTitle, thisArtist, thisArt));
} while (cursor.moveToNext());
}
}
Make sure table in which you are fetching the data having same column name
Check out this http://www.rjkfw.com/android/s3035.html
Check null before extracting data.
ListView audioListView = (ListView) findViewById(R.id.songView);
ArrayList<string> audioList = new ArrayList<>();
String[] proj = { MediaStore.Audio.Media._ID,MediaStore.Audio.Media.DISPLAY_NAME };// Can include more data for more details and check it.
Cursor audioCursor = getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, proj, null, null, null);
if(audioCursor != null){
if(audioCursor.moveToFirst()){
do{
int audioIndex = audioCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DISPLAY_NAME);
audioList.add(audioCursor.getString(audioIndex));
}while(audioCursor.moveToNext());
}
}
audioCursor.close();
ArrayAdapter<string> adapter = new ArrayAdapter<>(this,android.R.layout.simple_list_item_1,android.R.id.text1, audioList);
audioListView.setAdapter(adapter);
Error Solved, Since I was looking for album of particular song, null value is passed in cursor. so I changed my code of cursor as below:
public void getSong() {
ContentResolver contentResolver = getContentResolver();
Cursor cursor = contentResolver.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
new String[]{MediaStore.Audio.Media._ID,
MediaStore.Audio.Media.TITLE,
MediaStore.Audio.Media.ARTIST,
MediaStore.Audio.Media.ALBUM},
MediaStore.Audio.Media.IS_MUSIC + "=1",
null,
null);
if (cursor != null && cursor.moveToFirst()) {
do {
long thisId = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID));
String thisTitle = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE));
String thisArtist = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST));
String thisImage = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM));
songList.add(new Music(thisId, thisTitle, thisArtist, thisImage));
}while (cursor.moveToNext());
}
And I have tried by calling getsongImage(URI) method in playSong() in service class for getting Album as below:
public void getSongImage(Uri uri) {
MediaMetadataRetriever mmr = new MediaMetadataRetriever();
mmr.setDataSource(this,uri);
byte [] data = mmr.getEmbeddedPicture();
if(data==null){
activitySongDetailBinding.imgMusic.setImageResource(R.drawable.img);
}else {
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
activitySongDetailBinding.imgMusic.setImageBitmap(bitmap);
}
}
where uri=ContentUris.withAppendedId(
android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, songsArrayList.get(songPosn).getId())
I am building a music player that gets the BPM ID3v2 tag from all mp3 files on a device and allows sorting and filtering by BPM. To get the tag, I am using the mp3agic library. It turns out that this tag fetching takes some time for each song, and performing the fetch when adding each song to my list of songs renders the player without function for a while. I am not sure if I should use an AsyncTask on the entire list when it is done building or an AsyncTask for each item to retrieve its BPM and insert it into the song or even using some other, faster method of getting the BPM value. Can anyone offer any guidance?
Here is my code to get the BPM:
public int getBpmFromId(long id) {
int bpm = -1;
Uri uri = Uri.withAppendedPath(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, Long.toString(id));
try {
Mp3File file = new Mp3File(getRealPathFromURI(getApplicationContext(), uri));
if(file.hasId3v2Tag()) {
ID3v2 id3v2Tag = file.getId3v2Tag();
bpm = id3v2Tag.getBPM();
Log.d("MP3AGIC", "Got BPM for track: " + id + ": " + bpm);
}
} catch (Exception e) {
e.printStackTrace();
}
return bpm;
}
and here is the code I am using to build my list of songs:
public void getSongList() {
ContentResolver musicResolver = getContentResolver();
Uri musicUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
String selectionMimeType = MediaStore.Files.FileColumns.MIME_TYPE + "=?";
String selection = MediaStore.Audio.Media.IS_MUSIC + " != 0 AND " + selectionMimeType;
String sortOrder = null;
String[] projection = null;
String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension("mp3");
String[] selectionArgsMp3 = new String[] { mimeType };
Cursor musicCursor = musicResolver.query(musicUri, projection, selection, selectionArgsMp3, sortOrder);
if(musicCursor != null && musicCursor.moveToFirst()) {
int idColumn = musicCursor.getColumnIndex(MediaStore.Audio.Media._ID);
int titleColumn = musicCursor.getColumnIndex(MediaStore.Audio.Media.TITLE);
int artistColumn = musicCursor.getColumnIndex(MediaStore.Audio.Media.ARTIST);
do {
long id = musicCursor.getLong(idColumn);
String title = musicCursor.getString(titleColumn);
String artist = musicCursor.getString(artistColumn);
//bpm processing
int bpm = getBpmFromId(id);
songList.add(new Song(id, title, artist));
} while (musicCursor.moveToNext());
}
if(musicCursor != null)
musicCursor.close();
}
EDIT: It seems that what might be taking so long is getting the file path from the Uri, which is done in this method:
public String getRealPathFromURI(Context context, Uri contentUri) {
Cursor cursor = null;
try {
String[] proj = { MediaStore.Images.Media.DATA };
cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
} finally {
if (cursor != null) {
cursor.close();
}
}
}
I'm not sure how, or if I can, optimize this.
The decision to use one asynctask for the entire list or use the list as a queue for many asynctasks depends on your desire for concurrency.
If you plan to parallelize the tag-getting, then use multiple asynctasks (this would be good if the operation involves a lot of disk IO rather than CPU time).
Otherwise if you plan to execute them in sequence, then you should use only one asynctask. There is no need to create, then destroy tens/hundreds of background threads. This is inefficient.
Is there a way to query for genres in MediaStore and also find songs that don't have a genre set?
This code returns all songs that have a genre set but skips those that don't have a genre.
String[] proj1 = new String[]{
MediaStore.Audio.Genres.NAME,
MediaStore.Audio.Genres._ID
};
ContentResolver cr = activity.getContentResolver();
genreCursor = cr.query(MediaStore.Audio.Genres.EXTERNAL_CONTENT_URI, proj1, null, null, null);
if (genreCursor.moveToFirst()) {
while (genreCursor.moveToNext()) {
int index = genreCursor.getColumnIndexOrThrow(MediaStore.Audio.Genres.NAME);
String genre = genreCursor.getString(index);
index = genreCursor.getColumnIndexOrThrow(MediaStore.Audio.Genres._ID);
long genreId = Long.parseLong(genreCursor.getString(index));
Uri uri = MediaStore.Audio.Genres.Members.getContentUri("external", genreId);
Cursor tempCursor = cr.query(uri, projection, null, null, null);
if (tempCursor.moveToFirst()) {
while (tempCursor.moveToNext()) {
index = tempCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE);
String title = tempCursor.getString(index);
index = tempCursor.getColumnIndexOrThrow(MediaStore.Audio.Artists.ARTIST);
String artist = tempCursor.getString(index);
index = tempCursor.getColumnIndexOrThrow(MediaStore.Audio.Albums.ALBUM);
String album = tempCursor.getString(index);
songs.add(new Song(artist, title, album, genre));
}
tempCursor.close();
}
}
I am looking for a way to find those songs that have an unknown genre set. Is the only possibility to query all songs and then cross-check them with those that have a genre set to have a list of all songs with the genre for those that have it set?
Songs with unknown genre will have genre as "unknown". So, you'll be getting the the list of all the songs on the device.
I am using this code to scan all the songs with genres and store it in SQLitedatabase. Hope this will help you and this code also return genres.
int index;
int genres;
long genreId;
int count;
Uri uri;
Cursor genrecursor;
Cursor musicCursor;
db = new DBhelper(getApplicationContext()).getReadableDatabase();
String[] proj1 = {MediaStore.Audio.Genres.NAME, MediaStore.Audio.Genres._ID};
genrecursor=getApplicationContext().getContentResolver().query(MediaStore.Audio.Genres.EXTERNAL_CONTENT_URI,proj1,null, null, null);
if(genrecursor.moveToFirst())
{
do{
genres = genrecursor.getColumnIndexOrThrow(MediaStore.Audio.Genres.NAME);
System.out.println("GENRE NAME: "+genrecursor.getString(genres));
System.out.println("======================================");
index = genrecursor.getColumnIndexOrThrow(MediaStore.Audio.Genres._ID);
genreId=Long.parseLong(genrecursor.getString(index));
uri = MediaStore.Audio.Genres.Members.getContentUri("external", genreId);
musicCursor = getApplicationContext().getContentResolver().query(uri, null, null,null,null);
System.out.println("Total Songs: "+musicCursor.getCount());
if(musicCursor.moveToFirst())
{
int titleColumn = musicCursor.getColumnIndex
(android.provider.MediaStore.Audio.Media.TITLE);
int idColumn = musicCursor.getColumnIndex
(android.provider.MediaStore.Audio.Media._ID);
int artistColumn = musicCursor.getColumnIndex
(android.provider.MediaStore.Audio.Media.ARTIST);
int albumId = musicCursor.getColumnIndex
(MediaStore.Audio.Media.ALBUM_ID);
int data = musicCursor.getColumnIndex(MediaStore.Audio.Media.DATA);
int albumkey = musicCursor.getColumnIndex(MediaStore.Audio.Media.ALBUM_KEY);
int albumName = musicCursor.getColumnIndex(MediaStore.Audio.Media.ALBUM);
int artwork = musicCursor.getColumnIndex(MediaStore.Audio.Albums.ALBUM_ART);
do{
long thisId = musicCursor.getLong(idColumn);
String thisTitle = musicCursor.getString(titleColumn);
String thisArtist = musicCursor.getString(artistColumn);
long thisalbumId = musicCursor.getLong(albumId);
String thisdata = musicCursor.getString(data);
String AlbumKey = musicCursor.getString(albumkey);
String thisAlbum = musicCursor.getString(albumName);
String thisGenres = genrecursor.getString(genres);
ContentValues value = new ContentValues();
value.put("songtitle", thisTitle);
value.put("songartist", thisArtist);
value.put("songpath", thisdata);
value.put("songalbum", thisAlbum);
value.put("songgenres", thisGenres);
try {
db.insertOrThrow("songListRecord", null, value);
}
catch (SQLiteConstraintException e)
{
}
}while(musicCursor.moveToNext());
}
System.out.println("======================================");
}while(genrecursor.moveToNext());
}
I want to get songs and other MEDIA details from Album Id. All I have is Album Id and I tried many solutions but none of them succeed.
My code snippet:
ContentResolver contentResolver = getContentResolver();
Uri mediaUri = ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, albumId);
Log.wtf("SKJDBKJ", mediaUri.toString());
Cursor mediaCursor = contentResolver.query(mediaUri, null, null, null, null);
// if the cursor is null.
if(mediaCursor != null && mediaCursor.moveToFirst())
{
Log.wtf("DSJK", "entered cursor");
//get Columns
int titleColumn = mediaCursor.getColumnIndex(MediaStore.Audio.Albums.ALBUM);
int idColumn = mediaCursor.getColumnIndex(MediaStore.Audio.Media._ID);
int artistColumn = mediaCursor.getColumnIndex(MediaStore.Audio.Media.ARTIST);
// Store the title, id and artist name in Song Array list.
do
{
long thisId = mediaCursor.getLong(idColumn);
String thisTitle = mediaCursor.getString(titleColumn);
String thisArtist = mediaCursor.getString(artistColumn);
Log.wtf("Title", thisTitle);
// Add the info to our array.
songArrayList.add(new Song(thisId, thisTitle, thisArtist));
}
while (mediaCursor.moveToNext());
// For best practices, close the cursor after use.
mediaCursor.close();
}
Log for mediaUri returns path to current album, e.g. : content://media/external/audio/media/41.
Someone tell me how do I do it?
I have done it by myself.You can write simple sqlite query for 'selection' string on contentResolver.query .This example can show you how to get songs by album Id. I think this is best way.
ArrayList<Song> songs = new ArrayList<>();
String selection = "is_music != 0";
if (albumId > 0) {
selection = selection + " and album_id = " + albumId;
}
String[] projection = {
MediaStore.Audio.Media.TITLE,
MediaStore.Audio.Media.ARTIST,
MediaStore.Audio.Media.DATA,
MediaStore.Audio.Media.DISPLAY_NAME,
MediaStore.Audio.Media.DURATION,
MediaStore.Audio.Media.ALBUM,
MediaStore.Audio.Media.ALBUM_ID
};
final String sortOrder = MediaStore.Audio.AudioColumns.TITLE + " COLLATE LOCALIZED ASC";
Cursor cursor = null;
try {
Uri uri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
cursor = getActivity().getContentResolver().query(uri, projection, selection, null, sortOrder);
if (cursor != null) {
cursor.moveToFirst();
int position = 1;
while (!cursor.isAfterLast()) {
Song song = new Song();
song.setTitle(cursor.getString(0));
song.setDuration(cursor.getLong(4));
song.setArtist(cursor.getString(1));
song.setPath(cursor.getString(2));
song.setPosition(position);
song.setAlbumId(cursor.getLong(6));
cursor.moveToNext();
}
}
} catch (Exception e) {
Log.e("Media", e.toString());
} finally {
if (cursor != null) {
cursor.close();
}
}
I have figured it out myself after a LOT of trial and errors. I don't know if it's the best and safest way to do so, but as far as it's working I am happy.
I changed my code a bit and compared Album IDs. Here's the snippet:
ContentResolver contentResolver = getContentResolver();
Uri mediaUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
Log.wtf("SKJDBKJ", mediaUri.toString());
Cursor mediaCursor = contentResolver.query(mediaUri, null, null, null, null);
// if the cursor is null.
if(mediaCursor != null && mediaCursor.moveToFirst())
{
Log.wtf("DSJK", "entered cursor");
//get Columns
int titleColumn = mediaCursor.getColumnIndex(MediaStore.Audio.Media.TITLE);
int idColumn = mediaCursor.getColumnIndex(MediaStore.Audio.Media._ID);
int artistColumn = mediaCursor.getColumnIndex(MediaStore.Audio.Media.ARTIST);
int albumId = mediaCursor.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID);
// Store the title, id and artist name in Song Array list.
do
{
long thisId = mediaCursor.getLong(idColumn);
long thisalbumId = mediaCursor.getLong(albumId);
String thisTitle = mediaCursor.getString(titleColumn);
String thisArtist = mediaCursor.getString(artistColumn);
// Add the info to our array.
if(this.albumId == thisalbumId)
{
Log.wtf("SAME2SAME", String.valueOf(thisalbumId));
Log.wtf("SAME2SAME", String.valueOf(this.albumId));
songArrayList.add(new Song(thisId, thisTitle, thisArtist));
}
}
while (mediaCursor.moveToNext());
// For best practices, close the cursor after use.
mediaCursor.close();
}
I changed:
Albums to Media in MediaStore.Audio.Audio.xxx.
Got the album Id of Media.
Compared that to album Id I receive from bundle extras.
Only add those songs in the arrayList.
I guess this'll be the way for Artists too.
when you put the cursor.movenext function in to the while loop, the first line of
MediaStore database will be passed without saving the data because the function move the cursor and then check so its better to make a value instead of putting the movenext function into the while.
try {
Projection = new String[]{
MediaStore.Audio.Media.TITLE, MediaStore.Audio.Media.ALBUM
, MediaStore.Audio.Media.ARTIST,MediaStore.Audio.Media.DATA, MediaStore.Audio.Media.SIZE};
Cursor cursor = getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, Projection, null, null, null);
cursor.moveToFirst();
for (int i = 0; i < 5; i++) {
columns[i] = cursor.getColumnIndex(Projection[i]);
}
Music tempMusic = new Music();
while (next) {
tempMusic.setName(cursor.getString(columns[0]));
tempMusic.setAlbum(cursor.getString(columns[1]));
tempMusic.setArtist(cursor.getString(columns[2]));
tempMusic.setUri(cursor.getString(columns[3]));
tempMusic.setSize(cursor.getDouble(columns[4]));
if(!cursor.moveToNext())
{
next=false;
}
musicss.add(tempMusic);
tempMusic = new Music();
}
public Bitmap getAlbumArt(Long albumId) {
Bitmap albumArt = null;
try {
final Uri AlbumArtUri = Uri.parse("content://media/external/audio/albumart");
Uri uri = ContentUris.withAppendedId(AlbumArtUri, albumId);
ParcelFileDescriptor pfd = GlobalSongList.getInstance().getContentResolver().openFileDescriptor(uri, "r");
if (pfd != null) {
FileDescriptor fd = pfd.getFileDescriptor();
albumArt = BitmapFactory.decodeFileDescriptor(fd);
}
} catch (Exception e) {
}
return albumArt;
}
ALBUM_ID is a field in the MediaStore and you can query it in the same way you query for title,artist,etc.
public Long getAlbumId(String id)
{
Cursor musicCursor;
String[] mProjection = {MediaStore.Audio.Media._ID, MediaStore.Audio.Media.ALBUM_ID};
String[] mArgs = {id};
musicCursor = musicResolver.query(musicUri, mProjection, MediaStore.Audio.Media._ID + " = ?", mArgs, null);
musicCursor.moveToFirst();
Long albumId=musicCursor.getLong(musicCursor.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID));
return albumId;
}
This is how I did.
Works perfect.
String selection= MediaStore.Audio.Media.IS_MUSIC+"!=0";
String[] projection={
MediaStore.Audio.Media._ID,
MediaStore.Audio.Media.DATA,
MediaStore.Audio.Media.TITLE,
MediaStore.Audio.Media.ARTIST,
MediaStore.Audio.Media.ALBUM,
MediaStore.Audio.Albums.ALBUM_ID,
MediaStore.Audio.Media.DURATION
};
Cursor cursor=getActivity().managedQuery(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,projection,selection,null,"title asc");
List<String> data=new ArrayList<>();
List<String> songs=new ArrayList<>();
List<String> artists=new ArrayList<>();
List<String> albums=new ArrayList<>();
List<String> album_id=new ArrayList<>();
List<String> durations=new ArrayList<>();
cursor.moveToFirst();
while (cursor.moveToNext()){
if(cursor.getString(5).equals(mAlbumId)) {
data.add(cursor.getString(1));
songs.add(cursor.getString(2));
artists.add(cursor.getString(3));
albums.add(cursor.getString(4));
album_id.add(mAlbumId);
durations.add(cursor.getString(6));
}
}
I am trying to fetch the album art of all the songs present on the phone. I am using MediaStore to fetch all the songs title,artist etc. How should I fetch album art ? I tried using MediaMetaDataRetriever but getting confused how to use it for multiple files. Can anyone please tweak this code?
Activity class:
public void getSongList() {
// retrieve song info
ContentResolver musicResolver = getContentResolver();
Uri musicUri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
Cursor musicCursor = musicResolver.query(musicUri, null, null, null,
null);
metaRetriver.setDataSource(MainActivity.this,musicUri); // now how to loop over this
if (musicCursor != null && musicCursor.moveToFirst()) {
// get columns
int titleColumn = musicCursor.getColumnIndex(MediaColumns.TITLE);
int idColumn = musicCursor.getColumnIndex(BaseColumns._ID);
int artistColumn = musicCursor.getColumnIndex(AudioColumns.ARTIST);
// add songs to list
do {
long thisId = musicCursor.getLong(idColumn);
String thisTitle = musicCursor.getString(titleColumn);
String thisArtist = musicCursor.getString(artistColumn);
songList.add(new Song(thisId, thisTitle, thisArtist));
} while (musicCursor.moveToNext());
}
Once you have the album id, which you can get from that same cursor, you can query a different URI for the cover art path. see below for an example of approximately how I do it:
private static String getCoverArtPath(Context context, long androidAlbumId) {
String path = null;
Cursor c = context.getContentResolver().query(
MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI,
new String[]{MediaStore.Audio.Albums.ALBUM_ART},
MediaStore.Audio.Albums._ID + "=?",
new String[]{Long.toString(androidAlbumId)},
null);
if (c != null) {
if (c.moveToFirst()) {
path = c.getString(0);
}
c.close();
}
return path;
}
You could get a Map of all album art by id using something like this (untested)
private static Map<Long, String> getCoverArtPaths(Context context) {
String HashMap<Long, String> map = new HashMap<Long, String>();
Cursor c = context.getContentResolver().query(
MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI,
new String[]{MediaStore.Audio.Albums._ID, MediaStore.Audio.Albums.ALBUM_ART},
null,
null,
null);
if (c != null) {
for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()) {
map.add(c.getLong(0), c.getString(1));
}
c.close();
}
// returns a mapping of Album ID => art file path
return map;
}
I got it working like this. Hope it helps someone :)
public void getSongList() {
// retrieve song info
ContentResolver musicResolver = getContentResolver();
Uri musicUri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
Cursor musicCursor = musicResolver.query(musicUri, null, null, null,
null);
if (musicCursor != null && musicCursor.moveToFirst()) {
// get columns
int titleColumn = musicCursor.getColumnIndex(MediaColumns.TITLE);
int idColumn = musicCursor.getColumnIndex(BaseColumns._ID);
int artistColumn = musicCursor.getColumnIndex(AudioColumns.ARTIST);
int column_index = musicCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA);
// add songs to list
do {
long thisId = musicCursor.getLong(idColumn);
String pathId = musicCursor.getString(column_index);
Log.d(this.getClass().getName(), "path id=" + pathId);
metaRetriver.setDataSource(pathId);
try {
art = metaRetriver.getEmbeddedPicture();
Options opt = new Options();
opt.inSampleSize = 2;
songImage = BitmapFactory .decodeByteArray(art, 0, art.length,opt);
}
catch (Exception e)
{ imgAlbumArt.setBackgroundColor(Color.GRAY);
}
String thisTitle = musicCursor.getString(titleColumn);
String thisArtist = musicCursor.getString(artistColumn);
songList.add(new Song(thisId, thisTitle, thisArtist,songImage));
// if(songImage!=null)
// {
// songImage.recycle();
// }
} while (musicCursor.moveToNext());
}
For Fast rendering
If you are using recylerview, listview to render song list and it is making slow due to getting album art from song path then you can first check if ImageView has already background image set then don't process anything. It will reduce lot of processing and make scrolling fast even if song list is very large. I was facing same problem. I just did same as mentioned and recyclerview rendering with album art became smooth otherwise it was getting stuck during scroll.
My be this will help someone.
My code for recyclerview:
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
try {
if (holder instanceof MusicAdapter.MusicViewHolder) {
MusicAdapter.MusicViewHolder vh = (MusicAdapter.MusicViewHolder) holder;
vh.tvTitle.setText(musicList.get(position).title.toString());
vh.tvArtistAndAblum.setText(musicList.get(position).artist.toString() + " | " + musicList.get(position).album.toString());
Drawable background = vh.ivMusicIcon.getBackground();
if(background == null) {
String pathId = musicList.get(position).path;
MediaMetadataRetriever metaRetriver = new MediaMetadataRetriever();
metaRetriver.setDataSource(pathId);
try {
byte[] art = metaRetriver.getEmbeddedPicture();
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inSampleSize = 2;
Bitmap songImage = BitmapFactory.decodeByteArray(art, 0, art.length,opt);
BitmapDrawable ob = new BitmapDrawable(context.getResources(), songImage);
vh.ivMusicIcon.setBackground(ob);
}
catch (Exception e)
{
vh.ivMusicIcon.setImageResource(R.drawable.compact_disc);
}
}
} else if (holder instanceof FooterViewHolder) {
FooterViewHolder vh = (FooterViewHolder) holder;
}
} catch (Exception e) {
e.printStackTrace();
}
}