前幾天提到 Google UAMP 播放器專案,音樂列表的來源是從 Google 示範的 API 來的,因此在獲取音樂列表會參考 Google 的另外一個專案 storage-samples/MediaStore,這個專案是顯示手機內的圖片而非音樂,但經由前一天的介紹,得知概念是類似的。
在實作開始前先介紹一下整個專案會使用到的基本架構和相關 library,整體架構就使用 Google 推行的 Architecture Component,MVVM 架構搭配 LiveData,下有 Repository,再透過前一天介紹的方式獲取歌曲資訊。關於 DI 的使用先不會使用相關的 Library (Dagger2),怕會增加整個裝專案的複雜性,會使用手工 Inject 的方式,之後有機會用 Dagger2 來 Refactor。
關於撈取資料,需要 Thread 的處理會使用 Kotlin Coroutines,關於 Coroutines 並不會介紹太多用法,會直接拿來使用,關於 Coroutines 的觀念和用法可以參考這邊:
Android Target 會設定在 29,也就是 Android 10。Android 11 目前還在 Beta 3 的階段,快要正式 release 了,因此就還是先設定使用 Android 10,但 Android 11 有相關語法的改進,也會提出來分享。至於最低支援版本就設定 Android 5,開始引入 Material Design 的版本。
因為要讀取 App 外部的音檔,需要要在 AndroidManifest 加入相關的權限需求:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
此權限為 Dangerous 等級的,在 AndroidManifest 只是宣告而已,因此需要在程式執行時,使用者點擊權限許可之後,才算獲得此權限,
這邊就參考 MediaStore 專案的寫法:
要求 READ_EXTERNAL_STORAGE 的權限
private fun requestPermission() {
if (!haveStoragePermission()) {
val permissions = arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE)
requestPermissions(
permissions,
READ_EXTERNAL_STORAGE_REQUEST
)
}
}
確認是否取得權限
private fun haveStoragePermission() =
ContextCompat.checkSelfPermission(
requireContext(),
Manifest.permission.READ_EXTERNAL_STORAGE
) == PackageManager.PERMISSION_GRANTED
使用者點擊允許後,需要執行什麼行為,像我們就需要去顯示歌曲的列表
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
when (requestCode) {
READ_EXTERNAL_STORAGE_REQUEST -> {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Show song list
}
}
}
}
點開 App 後就會跳出 Dialog,進行詢問:
這三塊程式碼就可以完成權限行為相關的處理,但看起來還是有點繁瑣,在新的 activity-ktx 有做了改進,可以參考這篇,只要一個 code block 就可以完成上述的行為了,但目前還在 alpha 階段,之後正式發布,就可以加入簡化程式了。
程式碼在這邊,分支名稱(day4_get_permission):Fancy/day4_get_permission
Ref: