rokkonet

PC・Androidソフトウェア・アプリの開発・使い方に関するメモ

android開発 外部ストレージのメディアファイルのURI・ファイルパスの取得

2022 May 02.
2022 Apr. 30.
2022 Feb. 13.
2022 Jan. 30.
2021 Jul. 06.
2021 Jul. 04.

参考ページ 共有ストレージからメディア ファイルにアクセスする  |  Android デベロッパー  |  Android Developers

ContentResolverを利用して外部ストレージの共有領域のメディアファイル(audio video image)を読み込む


外部ストレージにユーザーが作成した任意のディレクトリ内に保存されたメディアファイルを読み込み可能

ContentResolverでのメディアファイル取得
 ContentResolverはMediaStoreの持っているContentProviderにアクセスし、結果を取得する。
 ContentProviderがデータベースサーバー、ContentResolverがクライアントに相当する。
 projectionにセットする値(Audioの場合)
  ID:MediaStore.Audio.Media._ID (URIそのものの取得に必要)
  ファイル名:MediaStore.Audio.Media.DISPLAY_NAME
  ファイルサイズ:MediaStore.Audio.Media.SIZE
  ファイルパス:"_data"


 URIそのものの取得には、下記サンプルのようにContentUris.withAppendedId()にIDを入れる。

val resolver = applicationContext.contentResolver
val query = resolver.query(....)
query?.use { cursor ->
    val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID)
    cursor.moveToFirst()
    val id = cursor.getLong(idColumn)
    val contentUri = ContentUris.withAppendedId(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, id)
}
query?.close()

確認端末

android 7
android 11
 ContentResolver#queryのcolumn projectionに _data を使っているが動作した。
 MediaStore.Audio.Media.DATAは"Deprecated in API level 29"だが _data は利用できる模様。

コンパイル環境

compileSdkVersion 31
minSdkVersion 24
targetSdkVersion 31

パーミッション

READ_EXTERNAL_STORAGEを要する

AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="....">

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

    <application

外部ストレージの音声ファイル情報をLogcatに表示するkotlinコード

MainActivity.kt

    // 事前に permission.READ_EXTERNAL_STORAGE を取得しておくこと

    fun readExMedia() {
        val collection =
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                MediaStore.Audio.Media.getContentUri(
                    MediaStore.VOLUME_EXTERNAL
                )
            } else {
                MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
            }

        val columns = arrayOf(
            MediaStore.Audio.Media._ID,
            MediaStore.Audio.Media.DISPLAY_NAME,
            MediaStore.Audio.Media.SIZE,
            "_data"
        )

        val resolver = applicationContext.contentResolver
        val query = resolver.query(    // オーディオファイルの集合を取得
            collection,  //データの種類
            columns, //取得する項目 nullは全部
            null, //フィルター条件 nullはフィルタリング無し
            null, //フィルター用のパラメータ
            null   //並べ替え
        )
        Log.d( "MyApp" , Arrays.toString( query?.getColumnNames() ) )  //項目名の一覧を出力
        val numCount = query?.count
        Log.d("MyApp", "Num raws : $numCount")  // オーディオファイル数

        query?.use { cursor ->
            val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID)
            val displayNameColumn =
                    cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DISPLAY_NAME)
            val sizeColumn = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.SIZE)
            val pathColumn = cursor.getColumnIndexOrThrow("_data")

            cursor.move(getRandomNum(numCount!!))    // オーディオファイルをランダムに1つ指定

            // 指定したオーディオファイルの各カラムのデータを取得する
            val id = cursor.getLong(idColumn)
            val displayName = cursor.getString(displayNameColumn)
            val mediaSize = cursor.getInt(sizeColumn)
            val contentUri: Uri = ContentUris.withAppendedId(
                MediaStore.Video.Media.EXTERNAL_CONTENT_URI, id)
            val PathOfUri = cursor.getString(pathColumn)

            // URI等を表示
            Log.d(
                "MyApp", "id: $id, name: $displayName, ${mediaSize}Byte, uri: $contentUri"
            )

            // パスを表示
            Log.d("MyApp", "Selected " + PathOfUri!!)
        }
        query?.close()
    }

    // 0以上、maxNum未満の範囲でランダムな数を1つ返す
    fun getRandomNum(maxNum: Int): Int {
        val random = Random()
        return random.nextInt(maxNum)
    }
}