如何禁止MediaScanner自动清除MediaProvider数据库中已拔掉U盘的数据
以Android O为例,MediaScanner文件的位置在如下路径:
frameworks/base/media/java/android/media/MediaScanner.java
Android系统中U盘扫描机制我会在下一篇文章里详细介绍,这里只简单说明一下该机制的基本流程。在设备挂载成功后, MediaProvider模块的MediaScannerReceiver会监听到StorageManagerService发来的"Intent.ACTION_MEDIA_MOUNTED"广播,最终会调到MediaScanner.scanDirectories(String[] directories)接口。进入该接口后,会调到prescan方法,该方法的作用是清除掉MediaProvider数据库中不存在的数据:
public void scanDirectories(String[] directories) {
try {
long start = System.currentTimeMillis();
prescan(null, true); //注意这里传的filePath参数为null
long prescan = System.currentTimeMillis();
...
private void prescan(String filePath, boolean prescanFiles) throws RemoteException {
Cursor c = null;
String where = null;
String[] selectionArgs = null;
mPlayLists.clear();
if (filePath != null) {
// query for only one file
where = MediaStore.Files.FileColumns._ID + ">?" +
" AND " + Files.FileColumns.DATA + "=?";
selectionArgs = new String[] { "", filePath }; //如果filePath不为null,则只query该path对应的内容
} else {
where = MediaStore.Files.FileColumns._ID + ">?";
selectionArgs = new String[] { "" }; //如果filePath为null, 则不限制query条件
}
...
while (c.moveToNext()) {
...
if (!exists && !MtpConstants.isAbstractObject(format)) {
// do not delete missing playlists, since they may have been
// modified by the user.
// The user can delete them in the media player instead.
// instead, clear the path and lastModified fields in the row
MediaFile.MediaFileType mediaFileType = MediaFile.getFileType(path);
int fileType = (mediaFileType == null ? 0 : mediaFileType.fileType);
if (!MediaFile.isPlayListFileType(fileType)) {
deleter.delete(rowId);
if (path.toLowerCase(Locale.US).endsWith("/.nomedia")) {
deleter.flush(); //删除不存在的内容
...
}
从代码可以发现,默认调prescan时传的filePath参数为null, 这就会导致在query的时候不限制条件,所有不存在的数据都会被清除。
解决办法:
public boolean scanDirectories(String[] directories) {
try {
long start = System.currentTimeMillis();
for (String path : directories) {
prescan(path, true); //将当前扫描设备的路径传递过去
}
这样一来,在prescan方法里,query的时候就只会处理当前扫描设备相关的数据,其它设备的数据不会被删除。