Android MediaScanner MediaProvider流程以及性能优化,音视频扫描
快速扫描
传送们: 快速扫描程序.
快速扫描部分数据量大的情况下比Android原生的MediaScanner快几十倍(我车机原生两万多音视频第一次扫描十几分钟,快速扫描10秒),缺点就是没有专辑、艺术家列表。UI部分我做的很随意,主要还是想快速实现,代码也很乱,之后会整理好。
简单效果:
[video(video-fWcdsuHl-1601061165426)(type-bilibili)(url-https://player.bilibili.com/player.html?aid=839660626)(image-https://img-blog.csdnimg.cn/img_convert/749c9eca2d929b923733cc6b60275858.png)(title-快速扫描)
一、源码解析
github链接
添加了多屏操作和手势识别,向左滑动可以把视频放到副屏播放,向上滑动退出视频播放。
github,欢迎交流.
MediaScanner时序图
链接:
MediaScanner时序图.
MediaSacannerReeiver.java
主要负责service的启动,接收android.intent.action.MEDIA_MOUNTED广播启动MediaScannerService
// An highlighted block
private void scan(Context context, String volume) {
Bundle args = new Bundle();
args.putString("volume", volume);
context.startService(
new Intent(context, MediaScannerService.class).putExtras(args));
}
MediaScannerService.java
第一次被启动走onCreate,将自己的线程启动
// A code block
@Override
public void onCreate() {
PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
StorageManager storageManager = (StorageManager)getSystemService(Context.STORAGE_SERVICE);
mExternalStoragePaths = storageManager.getVolumePaths();
// Start up the thread running the service. Note that we create a
// separate thread because the service normally runs in the process's
// main thread, which we don't want to block.
Thread thr = new Thread(null, this, "MediaScannerService");
thr.start();
}
第二次启动走onStartCommand,从广播里面获取信息发送给mServiceHandler,通过handler通知service启动线程扫描。
// An highlighted block
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
while (mServiceHandler == null) {
synchronized (this) {
try {
wait(100);
} catch (InterruptedException e) {
}
}
}
if (intent == null) {
Log.e(TAG, "Intent is null in onStartCommand: ",
new NullPointerException());
return Service.START_NOT_STICKY;
}
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent.getExtras();
mServiceHandler.sendMessage(msg);
// Try again later if we are killed before we can finish scanning.
return Service.START_REDELIVER_INTENT;
}
mServiceHandler 解析路径和volume信息然后开始扫描:
// An highlighted block
private final class ServiceHandler extends Handler {
@Override
public void handleMessage(Message msg) {
...
scan(directories, volume);
...
}
};
scan(String[] directories, String volumeName)方法中先 openDatabase(volumeName);发消息给MedaiProvider,让数据库先准备好,然后MediaScanner scanner = new MediaScanner(this, volumeName),scanner.scanDirectories(directories);MediaScanner.java开始扫描。
MediaProvider.java
MediaScanner.java
具体流程可以在上面提供的时序图查看,这里主要讲解几个重要的方法:
1、prescan
prescan主要是做老数据删除,先从数据库将数据读取出来,然后判断文件存不存在,不存在就删除。
// An highlighted block
private void prescan(String filePath, boolean prescanFiles) throws RemoteException {
Cursor c = null;
String where = null;
String[] selectionArgs = null;
mPlayLists.clear();//清除列表,这个列表后面用来保存每个媒体问的信息:id,修改时间等
if (filePath != null) {
//获取单个数据
// query for only one file
where = MediaStore.Files.FileColumns._ID + ">?" +
" AND " + Files.FileColumns.DATA + "=?";
selectionArgs = new String[] {
"", filePath };
} else {
//从数据库files表获取所有数据
where = MediaStore.Files.FileColumns._ID + ">?";
selectionArgs = new String[] {
"" };
}
mDefaultRingtoneSet = wasRingtoneAlreadySet(Settings.System.RINGTONE);
mDefaultNotificationSet = wasRingtoneAlreadySet(Settings.System.NOTIFICATION_SOUND);
mDefaultAlarmSet = wasRingtoneAlreadySet(Settings.System.ALARM_ALERT);
// Tell the provider to not de

最低0.47元/天 解锁文章
457





