Android源碼個個擊破之-多媒體掃描

最近公司產品有個需求:檢測到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);

        %相當於*,屬於通配符。

        

         android中通知系統掃描系統媒體文件的幾種方法

        常見的15種音頻格式

        android存儲路徑

        Android MediaProvider數據庫模式(對數據庫的每個表,每個字段做了詳盡的註釋。)

        Android多媒體數據庫詳解


        

  1. 加快U盤掃描的辦法

    1) http://cprs.patentstar.com.cn/Search/Detail?ANE=9CID3ADA9GEC9GGH7ECA9GDA8FCAAHGACIHAAHBA9IAB9GAB (該方法適用於提前知道目錄情況,哪些目錄有媒體文          件,哪些目錄沒有)

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

          此博文有一處寫錯的地方:

         image.png,這裏應該調用的是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盤仍然會重新掃描一遍,然後更新數據庫。

        

        



  

    



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章