此分析代码基于Android 6.0源码,转载请注明来源地址http://blog.csdn.net/lemon_blue/article/details/52262085
Media Data之多媒体扫描过程分析(一)
Media Data之多媒体扫描过程分析(二)
3. 如何使用多媒体扫描
介绍完多媒体的分析过程之后,接下来介绍一下我们怎么用多媒体扫描。
3.1发送广播
发送广播的方式比较简单,设置Intent并且传入要扫描的Uri即可。缺点是无法获取实时获取扫描状态,不利于更新操作,而且只能扫描单一文件。下面的例子是在下载应用中,对扫描的处理。
if (shouldScan) {
final Intent intent = new Intent(
Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
intent.setData(Uri.fromFile(file));
getContext().sendBroadcast(intent);
}
另外,对于其他项目使用此方法扫描,如下图:
3.2实现接口
实现接口的方法适合扫描实时返回结果的情况,例如下载文件时需要及时扫描下载成功的文件,并且更新UI;或者是蓝牙传输文件时,同样需要及时去扫描。下面的例子是在蓝牙功能中,对扫描的处理。其中MediaScannerNotifier是内部类,实现了
MediaScannerConnectionClient接口。
private static class MediaScannerNotifier implements MediaScannerConnectionClient {
private MediaScannerConnection mConnection;
private BluetoothOppShareInfo mInfo;
private Context mContext;
private Handler mCallback;
public MediaScannerNotifier(Context context, BluetoothOppShareInfo info, Handler handler) {
mContext = context;
mInfo = info;
mCallback = handler;
mConnection = new MediaScannerConnection(mContext, this);
if (V) Log.v(TAG, "Connecting to MediaScannerConnection ");
mConnection.connect();
}
public void onMediaScannerConnected() {
if (V) Log.v(TAG, "MediaScannerConnection onMediaScannerConnected");
mConnection.scanFile(mInfo.mFilename, mInfo.mMimetype);
}
public void onScanCompleted(String path, Uri uri) {
try {
if (uri != null) {
Message msg = Message.obtain();
msg.setTarget(mCallback);
msg.what = MEDIA_SCANNED;
msg.arg1 = mInfo.mId;
msg.obj = uri;
msg.sendToTarget();
} else {
Message msg = Message.obtain();
msg.setTarget(mCallback);
msg.what = MEDIA_SCANNED_FAILED;
msg.arg1 = mInfo.mId;
msg.sendToTarget();
}
} catch (Exception ex) {
Log.v(TAG, "!!!MediaScannerConnection exception: " + ex);
} finally {
if (V) Log.v(TAG, "MediaScannerConnection disconnect");
mConnection.disconnect();
}
}
}
另外,对于其他项目使用此方法扫描,如下图:
3.3使用静态方法
使用静态方法比较简单,不用调用connect方法,不用连接情况,可以传入路径数组,如果实现监听器会收到扫描结果。传入的参数分别为:上下文,路径数组,文件类型和监听器。
MediaScannerConnection.scanFile(this,
new String[] { path }, null,
new MediaScannerConnection.OnScanCompletedListener() {
//实现回调方法
public void onScanCompleted(String path, Uri uri) {
//回调方法中的参数即扫描结果
}
});
另外,对于其他项目使用此方法扫描,如下图:
4. 常见问题
4.1发送广播扫描无效
需要注意的是在MediaScannerReceiver.java中,对传入的路径有个判断,如下代码所示。可以看出对路径的判断是判断是否以/storage/emulated/0开头,如果不是不会去调用扫描操作的,所以在传入文件路径时要注意路径的问题。
if (Intent.ACTION_MEDIA_SCANNER_SCAN_FILE.equals(action) &&
path != null && path.startsWith(externalStoragePath + "/")) {
scanFile(context, path);
}
4.2 发送广播扫描文件夹
Uri data 必须是文件的Uri ,如果是文件夹的则不会起作用的,需要注意。如果有扫描文件夹的需求,需要先遍历文件夹所有文件然后循环发送广播,如果是子文件夹则继续循环迭代,下面的代码是示例。
public void fileScan(String file){
Uri data = Uri.parse("file://"+file);
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, data));
}
public void folderScan(String path){
File file = new File(path);
if(file.isDirectory()){
File[] array = file.listFiles();
for(int i=0;i<array.length;i++){
File f = array[i];
if(f.isFile()){//FILE TYPE
String name = f.getName();
if(name.contains(".mp3")){
fileScan(f.getAbsolutePath());
}
}
else {//FOLDER TYPE
folderScan(f.getAbsolutePath());
}
}
}
}
4.3是否阻塞当前线程
无论哪种扫描方式,其具体的扫描过程都是在MediaScannerService中进行的,MediaScannerService已经新建了工作线程处理,所以在调用扫描过程时,不必担心其阻塞当前线程。