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
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值