I once tried to use MediaScanner to resolve problems; however it turned out to be a failure. Now I make it.This post is to write down why I failed and how I work it out now. I think it could be deeper that other posts.
Android Media Scanning Mechanism
Android provides a great application for developers to add created media files to add them into the library. The application is called MediaProvider. Now let’s have a glance of MediaProvider.
The receiver part of its manifest
privatevoidscan(String[]directories,StringvolumeName){// don't sleep while scanningmWakeLock.acquire();ContentValuesvalues=newContentValues();values.put(MediaStore.MEDIA_SCANNER_VOLUME,volumeName);UriscanUri=getContentResolver().insert(MediaStore.getMediaScannerUri(),values);Uriuri=Uri.parse("file://"+directories[0]);sendBroadcast(newIntent(Intent.ACTION_MEDIA_SCANNER_STARTED,uri));try{if(volumeName.equals(MediaProvider.EXTERNAL_VOLUME)){openDatabase(volumeName);}MediaScannerscanner=createMediaScanner();scanner.scanDirectories(directories,volumeName);}catch(Exceptione){Log.e(TAG,"exception in MediaScanner.scan()",e);}getContentResolver().delete(scanUri,null,null);sendBroadcast(newIntent(Intent.ACTION_MEDIA_SCANNER_FINISHED,uri));mWakeLock.release();}
Actually the scan code is not really in the MediaScannerService
The above method maybe has been seen thousands of times. Actually it should work. However I failed and failed in sending broadcast intent. In the following section. I will point out why the sending broadcast not works. Even though you get well on with sending broadcast,it’s strongly recommended to read the Section Why Sending MEDIA_SCANNER_SCAN_FILE broadcast not works.
Use MediaScannerConnection
1234567891011
publicvoidmediaScan(Filefile){MediaScannerConnection.scanFile(getActivity(),newString[]{file.getAbsolutePath()},null,newOnScanCompletedListener(){@OverridepublicvoidonScanCompleted(Stringpath,Uriuri){Log.v("MediaScanWork","file "+path+" was scanned seccessfully: "+uri);}});}
the scanFile method is introduced since API 8
Create an instance and call scanFile (String path, String mimeType)
Use the second method by filled the second params with an array of paths.
Why Sending MEDIA_SCANNER_SCAN_FILE broadcast not works
Actually someone may think sending ACTION_MEDIA_SCANNER_SCAN_FILE works on some devices but not on other devices. Actually it’s. Is it a API limit?
No, It’s has someting to do with your file path.
Take a look at this
1234567891011121314151617181920212223
publicvoidonReceive(Contextcontext,Intentintent){Stringaction=intent.getAction();Uriuri=intent.getData();if(action.equals(Intent.ACTION_BOOT_COMPLETED)){// scan internal storagescan(context,MediaProvider.INTERNAL_VOLUME);}else{if(uri.getScheme().equals("file")){// handle intents related to external storageStringpath=uri.getPath();StringexternalStoragePath=Environment.getExternalStorageDirectory().getPath();Log.d(TAG,"action: "+action+" path: "+path);if(action.equals(Intent.ACTION_MEDIA_MOUNTED)){// scan whenever any volume is mountedscan(context,MediaProvider.EXTERNAL_VOLUME);}elseif(action.equals(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE)&&path!=null&&path.startsWith(externalStoragePath+"/")){scanFile(context,path);}}}}
Every part is right except the intent data. I mean the file path. You may hardcode the filepath. This is my example
So in the sending broadcast, your action is right, your data schema OK, your data path not null;but your path /sdcard/1390136305831_add.png does not startswith the externalStoragePath /mnt/sdcard/
And so the scan file is actually not called.
In conclusion your hardcoding path results in the failure.
Remove From Media Library
If we deleted a file ,it means that we need to remove the file from the media library.
Simply sending a broadcast?
Can we simple sending a broadcast to the MediaScannerReceiver? I also wish it could. But actually it does not work.
Look at this code for the explanation.
12345678910111213141516171819202122
// this function is used to scan a single filepublicUriscanSingleFile(Stringpath,StringvolumeName,StringmimeType){try{initialize(volumeName);prescan(path,true);Filefile=newFile(path);if(!file.exists()){returnnull;}// lastModified is in milliseconds on Files.longlastModifiedSeconds=file.lastModified()/1000;// always scan the file, so we can return the content://media Uri for existing filesreturnmClient.doScanFile(path,mimeType,lastModifiedSeconds,file.length(),false,true,MediaScanner.isNoMediaPath(path));}catch(RemoteExceptione){Log.e(TAG,"RemoteException in MediaScanner.scanFile()",e);returnnull;}}
As the above code points out, It does have a check before the real scanning.
Then how should I do?