「外部ストレージ_プライマリ」に保存されるメディアデータは、Media Storeと呼ばれる特別な方法でアクセスします。
他の方法も可能ですが、Media Storeが最も適した方法です。
別の記事で「メディアデータへMedia Storeでアクセス」する方法を、まとめました。
その記事は、基本的なアクセスとして「追加(insert)&読み書き」のみを説明しています。
この記事は、上記に加えて「参照(query)・更新(update)・削除(delete)」を説明します。
※環境:Android Studio Narwhal | 2025.1.1 Patch 1
目次
追加(insert)
以下の記事を参照
「ImagesデータへMedia Storeでアクセス(API≦28)」
「ImagesデータへMedia Storeでアクセス(API≧29)」
参照(query)
データベースを参照して、管理されているメディア情報の一覧を取得します。
ContentResolver#queryを用います。戻り値はCursorオブジェクトです。
Cursorオブジェクトは扱いにくいので、このサンプルはMediaDataのリストへ変換しています。
data class MediaData(val id: Long, val filename: String?, val filepath: String? = null) //
fun Context.queryMedia(uri: Uri): List<MediaData> { val _list = mutableListOf<MediaData>() val _projection = null // 取得するフィールド val _selection = null // 検索条件 val _selectionArgs = null // 検索条件の値 val _sortOrder = null // ソート順 try { contentResolver.query( uri, _projection, _selection, _selectionArgs, _sortOrder )?.use { cursor -> _list.parse(cursor) } } catch (e: Exception) { Log.i(TAG, e.toString()) } return _list.toList() } //
サンプルは以下の状態を元に実行した結果です。
# pwd /data/data/com.android.providers.media/databases # sqlite3 ./external.db sqlite> .headers on sqlite> .mode column sqlite> select _id,_display_name,_data from images; _id _display_name _data ---------- ----------------- ---------------------------------------------- 34 1754637551813.jpg /storage/emulated/0/Pictures/1754637551813.jpg 35 1754637551833.jpg /storage/emulated/0/DCIM/1754637551833.jpg 36 1754637551840.jpg /storage/emulated/0/Pictures/1754637551840.jpg 37 1754637551845.jpg /storage/emulated/0/DCIM/1754637551845.jpg
テーブル全体
val _contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI // val _contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI // val _contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI // val _contentUri = MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL) val _list = queryMedia(_contentUri) _list.dump(TAG) //
List size = 4 MediaData(id=34, filename=1754637551813.jpg, filepath=/storage/emulated/0/Pictures/1754637551813.jpg) MediaData(id=35, filename=1754637551833.jpg, filepath=/storage/emulated/0/DCIM/1754637551833.jpg) MediaData(id=36, filename=1754637551840.jpg, filepath=/storage/emulated/0/Pictures/1754637551840.jpg) MediaData(id=37, filename=1754637551845.jpg, filepath=/storage/emulated/0/DCIM/1754637551845.jpg)
任意のURI
val _contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI // val _contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI // val _contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI // val _contentUri = MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL) val _id = 34L val _uri = ContentUris.withAppendedId(_contentUri, _id) val _list = queryMedia(_uri) _list.dump(TAG)
List size = 1 MediaData(id=34, filename=1754637551813.jpg, filepath=/storage/emulated/0/Pictures/1754637551813.jpg)
更新(update)
データベースを参照して、管理されているメディア情報を更新します。
ContentResolver#updateを用います。戻り値は更新が成功した数です。
レコードの一部のフィールドは、ファイルとの物理的な関係が「固定」になっています。更新すると、Media Storeが破綻したり、ファイル名やバケット名に影響を与えたり、します。注意して下さい。
詳細は以下を参照
「Imagesデータのデータベースによる管理(API≦28)」
「Imagesデータのデータベースによる管理(API≧29)」
fun Context.updateMedia(uri: Uri, title: String): Int { val _selection = null // 検索条件 val _selectionArgs = null // 検索条件の値 val _contentValues = ContentValues().apply { put(TitleKey, title) } var _num = 0 try { _num = contentResolver.update( uri, _contentValues, _selection, _selectionArgs ) } catch (e: Exception) { Log.i(TAG, e.toString()) } return _num }
サンプルは以下の状態を元に実行した結果です。
# pwd /data/data/com.android.providers.media/databases # qlite3 ./external.db sqlite> .headers on sqlite> .mode column sqlite> select _id,_display_name,bucket_display_name,title from images; _id _display_name bucket_display_name title ---------- ----------------- ------------------- ------------- 38 1754637849272.jpg Pictures 1754637849272 39 1754637849282.jpg DCIM 1754637849282 40 1754637849286.jpg Pictures 1754637849286 41 1754637849294.jpg DCIM 1754637849294
テーブル全体
val _contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI // val _contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI // val _contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI // val _contentUri = MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL) val _num = updateMedia(_contentUri, "Birthday") Log.i(TAG, "Update number = ${_num}")
Update number = 4
sqlite> select _id,_display_name,bucket_display_name,title from images; _id _display_name bucket_display_name title ---------- ----------------- ------------------- ---------- 38 1754637849272.jpg Pictures Birthday 39 1754637849282.jpg DCIM Birthday 40 1754637849286.jpg Pictures Birthday 41 1754637849294.jpg DCIM Birthday
任意のURI
val _contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI // val _contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI // val _contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI // val _contentUri = MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL) val _id = 38L val _uri = ContentUris.withAppendedId(_contentUri, _id) val _num = updateMedia(_uri, "Birthday") Log.i(TAG, "Update number = ${_num}")
Update number = 1
sqlite> select _id,_display_name,bucket_display_name,title from images; _id _display_name bucket_display_name title ---------- ----------------- ------------------- ---------- 38 1754637849272.jpg Pictures Birthday 39 1754637849282.jpg DCIM 1754637849 40 1754637849286.jpg Pictures 1754637849 41 1754637849294.jpg DCIM 1754637849
削除(delete)
データベースを参照して、管理されているメディア情報を削除します。
ContentResolver#deleteを用います。戻り値は削除が成功した数です。
メディア情報が削除されると、メディア情報の_data(ファイルバス)が示すファイルも削除されます。
fun Context.deleteMedia(uri: Uri): Int { val _selection = null // 検索条件 val _selectionArgs = null // 検索条件の値 var _num = 0 try { _num = contentResolver.delete( uri, _selection, _selectionArgs ) } catch (e: Exception) { Log.i(TAG, e.toString()) } return _num }
サンプルは以下の状態を元に実行した結果です。
# pwd /data/data/com.android.providers.media/databases # qlite3 ./external.db sqlite> .headers on sqlite> .mode column sqlite> select _id,_display_name,bucket_display_name,title from images; _id _display_name bucket_display_name title ---------- ----------------- ------------------- ------------- 46 1754638782351.jpg Pictures 1754638782351 47 1754638782359.jpg DCIM 1754638782359 48 1754638782363.jpg Pictures 1754638782363 49 1754638782372.jpg DCIM 1754638782372
# pwd /storage/emulated/0 # ls -ld */* -rw-rw---- 1 root sdcard_rw 47891 2025-08-08 07:39 DCIM/1754638782359.jpg -rw-rw---- 1 root sdcard_rw 47891 2025-08-08 07:39 DCIM/1754638782372.jpg -rw-rw---- 1 root sdcard_rw 47891 2025-08-08 07:39 Pictures/1754638782351.jpg -rw-rw---- 1 root sdcard_rw 47891 2025-08-08 07:39 Pictures/1754638782363.jpg
テーブル全体
val _contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI // val _contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI // val _contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI // val _contentUri = MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL) val _num = deleteMedia(_contentUri) Log.i(TAG, "Delete number = ${_num}")
Delete number = 4
sqlite> select _id,_display_name,bucket_display_name,title from images; ※表示なし
# pwd /storage/emulated/0 # ls -ld */* ※表示なし
任意のURI
val _contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI // val _contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI // val _contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI // val _contentUri = MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL) val _id = 46L val _uri = ContentUris.withAppendedId(_contentUri, _id) val _num = deleteMedia(_uri) Log.i(TAG, "Delete number = ${_num}")
Delete number = 1
sqlite> select _id,_display_name,bucket_display_name,title from images; _id _display_name bucket_display_name title ---------- ----------------- ------------------- ------------- 47 1754638782359.jpg DCIM 1754638782359 48 1754638782363.jpg Pictures 1754638782363 49 1754638782372.jpg DCIM 1754638782372
# pwd /storage/emulated/0 # ls -ld */* -rw-rw---- 1 root sdcard_rw 47891 2025-08-08 07:39 DCIM/1754638782359.jpg -rw-rw---- 1 root sdcard_rw 47891 2025-08-08 07:39 DCIM/1754638782372.jpg -rw-rw---- 1 root sdcard_rw 47891 2025-08-08 07:39 Pictures/1754638782363.jpg
関連記事: