温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Android源码个个击破之-多媒体扫描

发布时间:2020-06-06 19:06:21 来源:网络 阅读:945 作者:屠夫章哥 栏目:移动开发

最近公司产品有个需求:检测到U盘插入,只扫描U盘里的歌曲(音频文件)


1.技术要点1-adb指令得出U盘存储的真实路径:

监听U盘挂载(ACTION_MEDIA_MOUNTED)后,执行shell指令。

 File file = new File("mnt/media_rw/usb_otg");
      if(file.exists()){
          ShellUtils.ShellResult shellResult = ShellUtils.execCommand("ls -l mnt/media_rw/usb_otg", true);
          if(!TextUtils.isEmpty(shellResult.successMsg)){
              MusicScanUtil.U_PATH = shellResult.successMsg.split("usb_otg ->")[1].trim();

              SPUtil.put(SPUtilKeys.U_PATH,MusicScanUtil.U_PATH);
              context.sendBroadcast(new Intent(MusicUIRefreshReceiver.ACTION));
              Toast.makeText(context, "U盘已经插入:" + usb.getAbsolutePath(), Toast.LENGTH_SHORT).show();
          }

        最终MusicScanUtil.U_PATH存储的就是类似storage/EFDE-UEYT或者 storage/78634982792这种路径,不同型号的U盘不一样。

        之所以要得出这个路径,是因为“context.getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,...)”扫描出来媒体文件,不光有内部存储的,还有SD卡和U盘上的,可以根据多媒体数据库表中的_data字段结合这个路径过滤U盘中的歌曲。

    

在测试的过程中,发现U盘里如果文件越多,媒体文件(视频)越多,则音频文件扫描出来的越慢。

  • 优化1:检索数据库优化

        getContentResolver().query()方法加上路径过滤条件。

    //selection: 指定查询条件
    String selection = MediaStore.Audio.Media.DATA + " like ?";
    
    String[] selectionArgs = {MusicScanUtil.U_PATH  + "%"};
    
    Cursor cursor = context.getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,  muiscInfoArray, selection, selectionArgs, null);

        %相当于*,属于通配符。

        

  • 优化2:多媒体文件扫描优化

       Android源码个个击破之-多媒体扫描

      分析多媒体数据库,会发现files表,不管啥文件,都会往里写东西。于是研究源码,看看这个数据库表是如何一步一步加载出来的。

  • MediaStore类介绍

      MediaStore 与Media.EXTERNAL_CONTENT_URI

      https://www.jianshu.com/p/c391ce8b6541  

      关于MediaStore.Files

      

  •   多媒体数据库

      https://www.jianshu.com/p/90832a323221  

      手机 db-wal db-shm 文件是什么数据?

      外接存储OTG  

      音乐播放器基本功能

         android中通知系统扫描系统媒体文件的几种方法

        常见的15种音频格式

        android存储路径

        Android MediaProvider数据库模式(对数据库的每个表,每个字段做了详尽的注释。)

        Android多媒体数据库详解


  • 多媒体数据库扫描源码分析

      Android media媒体库分析之:MediaProvider

      Android MediaProvider,MediaScanner媒体文件扫描源码解析

      Android开发——MediaProvider源码分析(1)(十分详细)

     深入理解MediaScanner 

        

  1. 加快U盘扫描的办法

    1) http://cprs.patentstar.com.cn/Search/Detail?ANE=9CID3ADA9GEC9GGH7ECA9GDA8FCAAHGACIHAAHBA9IAB9GAB (该方法适用于提前知道目录情况,哪些目录有媒体文          件,哪些目录没有)

    2)http://blog.sina.com.cn/s/blog_768100030101pohn.html  

          此博文有一处写错的地方:

         Android源码个个击破之-多媒体扫描,这里应该调用的是MediaScanner.cpp文件,不是java文件。

          此博文提出的最值得借鉴的方法是,MediaScanner.java的scanFile方法,非媒体文件就不要进行数据库操作了,我修改代码如下:

  2. @Override
            public void scanFile(String path, long lastModified, long fileSize,
                    boolean isDirectory, boolean noMedia) {
                // This is the callback funtion from native codes.
                // Log.v(TAG, "scanFile: "+path);
                Log.i("CZLog","scanFile: " + path);
    
                //CZFIX 增加588到622行代码 (在操作数据库之前提前判断媒体文件,不进行数据库操作。2019.7.20)
                boolean nextStep  = true;
                try {
                    FileEntry entry = beginFile(path, null, lastModified,
                            fileSize, isDirectory, noMedia);
    
                    // if this file was just inserted via mtp, set the rowid to zero
                    // (even though it already exists in the database), to trigger
                    // the correct code path for updating its entry
                    if (mMtpObjectHandle != 0) {
                        entry.mRowId = 0;
                    }
                    // rescan for metadata if file was modified since last scan
                    if (entry != null) {
                        if (noMedia) {
                            nextStep = false;
                            Log.i("CZLog","nextStep111111 = " + nextStep);
                        } else {
                            boolean isaudio = MediaFile.isAudioFileType(mFileType);
                            boolean isvideo = MediaFile.isVideoFileType(mFileType);
                            boolean isimage = MediaFile.isImageFileType(mFileType);
    
                            if (isaudio || isvideo || isimage) {
                                nextStep = true;
                            }else{
                                nextStep = false;
                                Log.i("CZLog","nextStep222222 = " + nextStep);
                            }
                        }
                    }else{
                        nextStep = false;
                        Log.i("CZLog","nextStep33333 = " + nextStep);
                    }
                } catch (Exception e) {
                    Log.e(TAG, "RemoteException in MediaScanner.scanFile()", e);
                    nextStep = false;
                    Log.i("CZLog","nextStep444444 = " + nextStep);
                }
                Log.i("CZLog","nextStep final= " + nextStep);
                if(nextStep == false) return;
    
                doScanFile(path, null, lastModified, fileSize, isDirectory, false, noMedia);
            }

    在doScanFile方法之前,我会判断文件是否是媒体文件,如果不是则不执行doScanFile,也就省略了数据库的操作。经测试,U盘扫描速度有所提高,但是200多首歌,扫描完还是得1分多钟。不知道到底是哪里慢呢

       

       ***同一U盘,首次插入设备,数据库查询不到歌曲信息,但是后面再插入(中间不得插入其他U盘),数据库就会有缓存信息,此时U盘仍然会重新扫描一遍,然后更新数据库。

        

        



  

    



向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI