Android4.4以上只能由系统应用发送广播通知系统扫描SD卡进而更新contentprovider的数据库,这个数据库在
可以导出来研究一下结构
4.4以及以下的通知系统刷新SD卡
IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MEDIA_SCANNER_STARTED);
intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_STARTED);
intentFilter.addDataScheme("file");
App.getINSTANCE().sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" +
Environment.getExternalStorageDirectory())));
4.4以上替代广播的方案
可以用MediaScannerConnection类,有俩种使用方式
一 用MediaScannerConnection的静态方法
/**
* @param context 上下文
* @param 查询的路径数组(这里也没说目录行不行,试了目录的好像不行,个人觉得还是用具体文件,下面会有解决方案)
* @param mimeTypes 文件类型,具体对应表看文底部,这个可选,如果为null,则用扫到的后缀名作为mimeTypes
* @param callback 扫描监听器,可选
* 更多内容看官方API
*/
public static void scanFile(Context context, String[] paths, String[] mimeTypes,
OnScanCompletedListener callback) {
....隐藏内部实现...
}
上面也说了,第二个参数填目录名时不能正确扫描更新SD卡,不知道为啥,有知道的老铁麻烦告知,个人的替代方案是用具体的文件名来代替,先用File扫描所有的文件,然后再把扫到的文件的数组传入那个MediaScannerConnection.scanFile()中进行更新。
例如这里以扫描歌曲为例子,
//保存歌曲绝对路径的数组,这个用于MediaScannerConnection.scanFile()第二个参数
String[] songTotalPath = null;
//现在假设要扫描sd卡下的opo目录,“/”这个斜杠别丢了,接下来用到的file相关方法啊啥的建议参考下File的类文档
File f = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/opo");
if (f.isDirectory()) {
//测试f这个路径表示的文件是否是一个目录
File[] files = f.listFiles();//返回一个抽象(绝对)路径名数组,这些路径名表示此抽象路径名表示的目录中的文件
if (files != null) {
//初始化数组长度
songTotalPath = new String[files.length];
for (int i = 0; i < songTotalPath.length; i++) {
//默认路径,这里初始化数组每一项,只是单纯的防止后面用第二种方式扫描文件带来的空指针异常,无实际意义
songTotalPath[i] = Environment.getExternalStorageDirectory().getAbsolutePath();
}
for (int i = 0; i < files.length; i++) {
if (files[i].isFile()) {
//如果 扫到的是文件,那么把具体路径存到songTotalPath下
songTotalPath[i] = Environment.getExternalStorageDirectory().getAbsolutePath() + "/opo/" + files[i].getName();
}
}
}
}
//这里就可以直接用了,第三个这里用文件的后缀名,为空
MediaScannerConnection.scanFile(App.getINSTANCE(), songTotalPath, null, new MediaScannerConnection.OnScanCompletedListener() {
@Override
public void onScanCompleted(String path, Uri uri) {
//扫描完成时逻辑
}
});
第二种 MediaScannerConnection.MediaScannerConnectionClient
这种方法就有点麻烦了,同样传入目录路径也是有问题,然后这里是
封装成了一个类MediaScanner,具体是
- 先创建MediaScanner类实现MediaScannerConnection.MediaScannerConnectionClient的俩个方法
@Override
public void onMediaScannerConnected() {
}
@Override
public void onScanCompleted(String path, Uri uri) {
}
- 在MediaScanner类中创建MediaScannerConnection的对象
并在构造函数中初始化 - 在onMediaScannerConnected方法中连接IMediaScannerService服务,只要调用就绑定了
mediaScannerConnection.connect();
并且开始用参数扫描文件
mediaScannerConnection.scanFile(filePaths[i], mimeTypes[i]);
感觉第一种就是第二种的封装版
MediaScanner类如下
package com.minminaya.bogemusic.utils.localmusic;
import android.content.Context;
import android.media.MediaScannerConnection;
import android.net.Uri;
/**
* Created by Niwa on 2017/5/29.
*/
public class MediaScanner implements MediaScannerConnection.MediaScannerConnectionClient {
private MediaScannerConnection mediaScannerConnection = null;
public MediaScanner(Context context) {
mediaScannerConnection = new MediaScannerConnection(context, this);
}
private String[] filePaths;
private String[] mimeTypes;
public void scanFiles(String[] filePaths, String[] mimeTypes) {
this.filePaths = filePaths;
this.mimeTypes = mimeTypes;
mediaScannerConnection.connect();
}
@Override
public void onMediaScannerConnected() {
for (int i = 0; i < filePaths.length; i++) {
mediaScannerConnection.scanFile(filePaths[i], mimeTypes[i]);
}
filePaths = null;
mimeTypes = null;
}
private int scanTimes = 0;
@Override
public void onScanCompleted(String path, Uri uri) {
// scanTimes++;
// if (scanTimes == filePaths.length) {
mediaScannerConnection.disconnect();
// scanTimes = 0;
// }
}
}
使用方法,在view(Activity或者Fragment)的启动生命周期中
首先也是要扫描文件,这个和第一种的扫描文件基本复用的,只是中间加了防止后面调用mimeTypes数组空指针异常的初始化数组逻辑
//保存歌曲绝对路径的数组,这个用于MediaScannerConnection.scanFile()第二个参数
String[] songTotalPath = null;
String[] mimeTypes = null;
//现在假设要扫描sd卡下的opo目录,“/”这个斜杠别丢了,接下来用到的file相关方法啊啥的建议参考下File的类文档
File f = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/opo");
if (f.isDirectory()) {
//测试f这个路径表示的文件是否是一个目录
File[] files = f.listFiles();//返回一个抽象(绝对)路径名数组,这些路径名表示此抽象路径名表示的目录中的文件
if (files != null) {
//初始化数组长度
songTotalPath = new String[files.length];
mimeTypes = new String[files.length];
for (int i = 0; i < songTotalPath.length; i++) {
//默认路径,这里初始化数组每一项,只是单纯的防止后面用第二种方式扫描文件带来的空指针异常,无实际意义
songTotalPath[i] = Environment.getExternalStorageDirectory().getAbsolutePath();
//只是单纯的防止后面用第二种方式扫描文件带来的空指针异常
mimeTypes[i] = null;
}
for (int i = 0; i < files.length; i++) {
if (files[i].isFile()) {
//如果 扫到的是文件,那么把具体路径存到songTotalPath下
songTotalPath[i] = Environment.getExternalStorageDirectory().getAbsolutePath() + "/opo/" + files[i].getName();
Log.e("file", files[i].getName());
}
}
}
}
MediaScanner mediaScanner = new MediaScanner(App.getINSTANCE());
String[] filePaths = songTotalPath;
//MimeType文件也可以这个获取,如果不知道媒体文件对应的的值
// String[] mimeTypes = new String[]{MimeTypeMap.getSingleton().getMimeTypeFromExtension("mp3")};
// String[] mimeTypes = new String[]{null};
mediaScanner.scanFiles(filePaths, mimeTypes);
MimeTypes说明
MimeTypes大全集
MediaScannerConnection
end