I have videoplayer app with filebrowser listing all videos on SD card
Code inspired by i want get audio files in sd card
Using ContentResolver, works as expected, but it does not update if the files on card change. I do not mean automatically, but after view/app restart. Not even reinstalling the application helped, still shows the same files. The deleted video file is not visible via PC nor it is possible to play it (This video cannot be played (translation)).
I dumped the data and the problem is not in view caching or elsewhere. I do not implement any caching of my own and failed to find anything on the matter. Thank you
Code:
// acquisition
String[] projection = {
MediaStore.Video.Media._ID,
MediaStore.Video.Media.DISPLAY_NAME,
MediaStore.Video.Media.DURATION,
MediaStore.Video.Media.DATA
};
ContentResolver resolver = getActivity().getContentResolver();
Cursor videoCursor = resolver.query(
MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
projection,
null,
null,
null
);
// extraction
while(cursor.moveToNext()) {
cursorIndex = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA);
filepath = cursor.getString(cursorIndex);
cursorIndex = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DISPLAY_NAME);
filename = cursor.getString(cursorIndex);
cursorIndex = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATION);
duration = cursor.getString(cursorIndex);
result[ index++ ] = new VideoFileMetadata(filename, duration, filepath);
}
Edit 1 [14-03-2013]:
I tried adding number + " = " + number to ORDER or WHERE clause to act as a potential query caching buster, but it had no effect (although it's possible it was removed by an optimizer as a useless clause). This time I had reinstalled the application from a different machine using different certificate, but the query result remained the same, listing currently non-existing files.
You should first call cursor.moveToFirst() .
So, your cursor iteration loop should look like
if (cursor.moveToFirst()) {
do {
// cursorIndex = cursor.getColumnIndexOrThrow, etc...
} while (cursor.moveToNext());
}
Related
Using this method of audio file retrieval from Android's external storage
Cursor cursor = getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, null, null, null);
can I actually find a resonable way to fetch a genre of the given song? MediaStore class seems to provide everything else - from song's title to its composer info - except for the genre field. Should I use MediaMetadataRetriever then? If so, how drastically can creating a MediaMetadataRetriever instance for every song on a device reduce app's performance?
Maybe there are some better ways to retrieve all audio files from both external and internal storages in android?
As mentioned at Developer's Site,
You can fetch the Genres of the Audio file using MediaStore.Audio.Genres
Sample Code :
private static String[] genresProj = {
MediaStore.Audio.Genres.NAME,
MediaStore.Audio.Genres._ID
};
int idIndex = cursor
.getColumnIndexOrThrow(MediaStore.Audio.Media._ID);
while (cursor.moveToNext()){
int id = Integer.parseInt(mediaCursor.getString(idIndex));
Uri uri = MediaStore.Audio.Genres.getContentUriForAudioId("external", id );
genresCursor = context.getContentResolver().query(uri,
genresProj , null, null, null);
int genreIndex = genresCursor.getColumnIndexOrThrow(MediaStore.Audio.Genres.NAME);
while (genresCursor.moveToNext()) {
Log.d(TAG, "Genre = " +genresCursor.getString(genreIndex));
}
}
}
To fetch other details of the Audio file, please check here .
I'm creating a music player that populates an array list with song objects. Each song object has a series of attributes. One of those attributes is the album-art URI.
This is the line of code where I assign the URI attribute to the song object.
songObject.albumArtURI = GetAlbumArtURI(albumID);
Here is the string value of albumID
Log.v("TAG",String.valueOf(albumID)); // prints [Ljava.lang.String;#44ce53d
When I pass albumID to GetAlbumArtURI() method
private String GetAlbumArtURI(String[] albumID){
final Cursor mCursor = getContentResolver().query(
MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI,
new String[] {MediaStore.Audio.Albums.ALBUM_ART},
MediaStore.Audio.Albums.ALBUM_ID + "=?",
albumID, // Error
null
);
return mCursor.getString(0);
}
I get this error:
no such column: album_id (code 1)
while compiling:
SELECT album_art FROM album_info WHERE (album_id=?)
The error essentially says that table album_info does not contain album_id column. But according to the documenation, album_info does have such a column.
So there's a few issues causing your query to return nothing and throw that error.
MediaStore.Audio.Albums.ALBUM_ID is not the column you want to reference. You should be using MediaStore.Audio.Albums._ID.
You need to move your cursor's read position to the first position when you get results, if possible. Doing otherwise will result in you never getting the results you need
The way that MediaStore works on android is that you have to register the media files that you want the OS to know about - this isn't automatic. You need to implement something similar to the SingleMediaScanner described in this thread
Here is the working bit of code that I have written:
try {
final Cursor mCursor = getContentResolver().query(
MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI,
new String[] {MediaStore.Audio.Albums.ALBUM_ART},
MediaStore.Audio.Albums._ID + "=?",
null,
null
);
// You need to check if there are results in your cursor.
// This is like saying if(mCursor.getCount() > 0)
if(mCursor.moveToFirst()) {
return mCursor.getString(mCursor.getColumnIndex(MediaStore.Audio.Albums.ALBUM_ART));
} else {
return "";
}
} catch (Exception e) {
Log.e(this.getClass().getSimpleName(),e.getMessage());
}
When you have called that code, you're assuming that the MediaStore on your device knows about the music files you've downloaded or added. You can definitely implement a BroadcastReceiver to capture system events like files being added, but for this answer I'm just going to show how you account for one known file. You could also expand this to search an entire directory by adding to the onMediaScannerConnected(...) method.
If you implement the SingleMediaScanner file found here you can then just do:
File file = new File(Environment.getExternalStorageDirectory() + "/Download/1.mp3");
SingleMediaScanner singleMediaScanner = new SingleMediaScanner(this, file);
And it will register the media file in your MediaStore. At that point, you should be able to get results back from your query above. If you are having doubts of whether or not the songs are being registered, you can check to see if any records have been added at all by changing your mCursor call to this (to get all the results in the media store) and then iterating through them:
final Cursor mCursor = getContentResolver().query(
MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI,
null,
null,
null,
null
);
I'm using org.apache.commons.io.FileUtils to move files from one directory to another, like so:
File source = new File("/my/image/directory/image.jpg";
File destination = new File("/new/image/directory/image.jpg");
FileUtils.moveFile(source, destination);
Note that the source directory is an external directory and destination is an internal directory.
After above code is executed, I query to get the files of my internal directory like so:
File vaultDir = ctx.getDir("dir_name", Context.MODE_PRIVATE);
String[] fileList = vaultDir.list();
//Iterate and print file names
This is working as intended. But when i query the MediaStore like so:
ArrayList<GridViewObject> objects = new ArrayList<>();
String[] mProjection = {MediaStore.Images.Media.DISPLAY_NAME,
MediaStore.Images.Media.DATA};
ContentResolver cr = ctx.getContentResolver();
Cursor mCursor = cr.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
mProjection,
null,
null,
MediaStore.Images.Media.DEFAULT_SORT_ORDER);
mCursor.moveToFirst();
while (!mCursor.isAfterLast()) {
GridViewObject tmpGridViewObject = new GridViewObject();
tmpGridViewObject.setTitle(mCursor.getString(0));
tmpGridViewObject.setUrl(mCursor.getString(1));
objects.add(tmpGridViewObject);
mCursor.moveToNext();
}
The image is still returned to me by the query. Also, when I open my camera gallery app, the image is still there, as if it was never deleted.
I noticed that if I restart the phone, the image disappears from my device camera gallery app as intended (and above query return correct result). So I think it might be an indexing problem.
What do I need to do to "update" the MediaStore to show the intended result?
I solved this by instead of deleting the file using FileUtils.delete(srcFile, destFile); i copied the the file using FileUtils.copy(srcFile, destFile); and then to refresh MediaStore i used the following code to delete the source entry:
String selection = MediaStore.Images.Media.DATA + "='" + source.getAbsolutePath() + "'";
ctx.getContentResolver().delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection, null);
Credit goes to Pascal's answer to this question.
I'm searching Musicfiles via
proj = new String[] {[...],
MediaStore.Audio.Media.DATA
};
Cursor musiccursor = context.getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,proj, MediaStore.Audio.Media.IS_MUSIC + "=1", null, null);
[...]
int ixdata = musiccursor.getColumnIndex(MediaStore.Audio.Media.DATA);
[...]
while(musiccursor.moveToNext()) {
[...]
String data = musiccursor.getString(ixdata);
with files on /mnt/sdcard everything works just fine, but unfortunately with files in /mnt/USB data seems to be empty.
What's even worse is that the mediaplayer works with the content-URI of files in /mnt/sdcard (i.e. content://media/external/audio/media/120) but not with the content-URIs of files in /mnt/USB (i.e. content://media/external/audio/media/530).
The files are alright, i can play them fine when i give the mediaplayer the absolute path to i.e. /mnt/USB/testfile.mp3
Even weirder: Album, Artist, Title etc. are read without problems from the files on the USB-Drive
anyone an idea?
Thanks
I've asked myself the very same question, but I did not manage to find the reason why the mediastore contains rows with empty data.
What I came up with is adding a "where clause" in the query to the mediastore by not-selecting the items with and empty data field (filtering the empty data source).
Cursor cursor = managedQuery(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
MY_COLUMNS,
MediaStore.Audio.Media.DATA + "<> ''",
null,
SORT_ORDER);
where
MY_COLUMNS is a String[] containing my columns'names
SORT_ORDER is my sorting order option
A project I'm currently working on requires the application to discover all audio tracks on an android device. In addition to the tracks, it must also be able to group them by album and artist.
I found the MediaStore content provider and set about creating a database helper utility class to quickly return the IDs of tracks, albums and artists. I have been able to query the Media Store which returns some result, but it appears that not all of the audio information is stored there.
For example, querying for all artists returns only 9 results, but the Android Music Player application returns 27.
I am using the following code to query the artists:
ContentResolver resolver = getContentResolver();
String[] projection = new String[]{MediaStore.Audio.ArtistColumns.ARTIST};
Uri uri = android.provider.MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI;
Cursor c = null;
try {
c = resolver.query(uri, projection, null, null, null);
}
catch (UnsupportedOperationException e) {
Log.e("DatabaseHelper", "query: " + e);
c = null;
}
if(c != null) {
while(c.isAfterLast() == false) {
Log.e("ARTIST", "NAME: " + cursor.getString(0));
cursor.moveToNext();
}
}
It seems as if the Media Scanner (which is definatley run when my device boots up) is not detecting much of my audio library. Am I doing something wrong?
I am simply trying to find all audio tracks, audio albums and audio artists quickly and efficiently. If MediaStore can't help me then I fear I will have to implement some form of file scanner to traverse directory structures and build my own database, but I don't want to do that ;)
Any thoughts would be much appreciated.
Thanks.
Probably, You should also query android.provider.MediaStore.Audio.Albums.INTERNAL_CONTENT_URI to get the rest visible in media player.