【安卓】Media媒體庫與異步查詢

一:觀察Device File Explorer

  1. System目錄下的app目錄
    在這裏插入圖片描述
  2. 同級System目錄下的Priv-app目錄
    在這裏插入圖片描述
  3. Priv-app目錄下存在MediaProvider目錄,裏面有個app,功能是掃描手機中的媒體類文件
    在這裏插入圖片描述

二:找到儲存的對應數據庫位置

  1. data目錄和system同級。6.0以後就看不見了,應該是沒權限,之後動態獲取就好了在這裏插入圖片描述
  2. 導出數據庫就可以看到字段結構了
    在這裏插入圖片描述

三.加載音樂數據

  1. 需要拿到數據庫內容就要用四大組件裏的內容解析者ContentResolver,新建對象,通過該對象連接服務器,查詢語言
  val resolver= context?.contentResolver
        //cursor是查詢的返回類型 前車之鑑 放到主線程卡死 加到子線程中 完成再更新UI適配
        val cursor=resolver?.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
            arrayOf(MediaStore.Audio.Media.DATA,
                    MediaStore.Audio.Media.SIZE,
                    MediaStore.Audio.Media.DISPLAY_NAME,//title可能會有編碼問題
                    MediaStore.Audio.Media.ARTIST),
            null,null,null)//查詢感興趣的字段 數組封裝 後三個參數排序什麼的
            //打印所有數據
            CursorUtil.logCursor(cursor)*/
  1. 寫個遍歷cursor的方法
object CursorUtil {
    fun logCursor(cursor: Cursor?){
        cursor?.let {
            //將遊標復位
            //count是cursor含有的條目個數
            //columnCount是每個條目含有的字段
            it.moveToPosition(-1)
                while (it.moveToNext()){
                    for (index in 0 until it.columnCount)//每個字段對應的位置[)
                    {
                        println("key=${it.getColumnName(index)} --value=${it.getString(index)}")
                    }
                }
        }
    }
}
  1. 運行結果,展示一條記錄
    在這裏插入圖片描述

四.異步查詢

1. 異步查詢可以開啓新線程,完成後再更新界面,避免堵塞進程,前車之鑑就是這個,剛打開應用一片白,而且還加載專輯圖片,堵的不要不要,運氣不好直接就閃退了。

在這裏插入圖片描述

2. 開啓線程

方法一:使用Thread開啓子線程,並使用Handler回調給主線程,進行線程間通信(相對麻煩,還要解決線程問題)

     //開啓一個單獨的線程查詢音樂數據
       Thread(object :Runnable{
            override fun run() {
                val cursor=resolver?.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
                    arrayOf(MediaStore.Audio.Media.DATA,
                        MediaStore.Audio.Media.SIZE,
                        MediaStore.Audio.Media.DISPLAY_NAME,
                        MediaStore.Audio.Media.ARTIST),
                    null,null,null)
                //這裏通過handler的方法將查詢到的cursor傳入主線程
                val msg =Message.obtain()//消息池中拿消息
                msg.obj=cursor
                handler.sendMessage(msg)
            }

        }).start()

需要一個handler對象實現方法,即使用匿名內部類

/*    val handler = @SuppressLint("HandlerLeak") object : Handler(){//os包
        //new Handler要複寫其方法,所以用匿名內部類
        override fun handleMessage(msg: Message) {//接收消息
            msg.let {
                val cursor=msg.obj as Cursor
                CursorUtil.logCursor(cursor)
            }
        }
    }*/

方法二:安卓提供的繼承AsyncTask類(專門用於處理異步任務)

  1. initData外創建AudioTask類繼承AsyncTask
//因爲查詢使用的是ContentProvider(內容提供者對應resolver)

    //音樂查詢異步任務
    class AudioTask:AsyncTask<ContentResolver,Void,Cursor>(){//三個泛型 參數 進度 返回的Result類型
        //1.後臺開啓新線程執行任務 相當於new一個新handler
        override fun doInBackground(vararg params: ContentResolver?): Cursor ?{//第一個參數是content 傳過來的返回結果是Cursor 我們這邊就一個參數拿出來就好了
            val cursor=params[0]?.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
                arrayOf(MediaStore.Audio.Media.DATA,
                    MediaStore.Audio.Media.SIZE,
                    MediaStore.Audio.Media.DISPLAY_NAME,
                    MediaStore.Audio.Media.ARTIST),
                null,null,null)
            return cursor
        }
        //2.後臺任務結果回調到主線程
        override fun onPostExecute(result: Cursor?) {
            super.onPostExecute(result)
            //打印Cursor
            CursorUtil.logCursor(result)
        }
    }
  1. initData補充,將resolver傳過去
  val resolver= context?.contentResolver
  
  AudioTask().execute(resolver)//第二種異步傳遞的參數params可變參數後面取也取第一個就好了()只一個參數
  

方法三:安卓提供的繼承AsyncQueryHandler類(專門用於處理數據庫的操作)註釋的運用

  val resolver= context?.contentResolver

  val handler= @SuppressLint("HandlerLeak") object:AsyncQueryHandler(resolver){//token是用於區分的 調用查詢可以加入token 同flag
            override fun onQueryComplete(token: Int, cookie: Any?, cursor: Cursor?) {
                //查詢完成的回調  只有回調是在主線程中的
            //打印數據
            CursorUtil.logCursor(cursor)
          /*  when(token){條目或者非常多 內嵌語句非常多 就可以考慮用cookie傳遞adapter  startquery中第二個參數,現在沒適配adapter先寫null
                0->adapter1
                1->adapter2

            }*/
            }
        }
        //開始查詢 如果與n個startquery要加識別token
        handler.startQuery(0,null,MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
            arrayOf(MediaStore.Audio.Media.DATA,
                MediaStore.Audio.Media.SIZE,
                MediaStore.Audio.Media.DISPLAY_NAME,
                MediaStore.Audio.Media.ARTIST),
            null,null,null)

在這裏插入圖片描述
start方法對應on方法獲取結果

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