「外部ストレージ_プライマリ」に保存されるメディアデータは、データベースで管理されます。
Media Storeを使うと、このデータベースを通してメディアデータへアクセスできます。
データベース(SQLite)が持つ検索機能を使ってアクセス対象を絞り込めるので、とても便利です。
この記事は、「絞り込アクセス」について、まとめます。
※環境:Android Studio Narwhal | 2025.1.1 Patch 1
目次
絞り込みアクセス
メディアデータへMedia Storeでアクセスする際に、次のコマンドが使われます。
- ContentResolver#query … メディア情報の参照
- ContentResolver#update … メディア情報の更新
- ContentResolver#delete … メディア情報の削除
これらのコマンドは、アクセス対象のメディア情報を絞り込む機能があります。
@Nullable public final Cursor query( @NonNull Uri uri, @Nullable String[] projection, // 取得するカラム @Nullable String selection, // 検索条件 @Nullable String[] selectionArgs, // 検索条件の値 @Nullable String sortOrder // ソート順 ) { ... }
public final int update( @NonNull Uri uri, @Nullable ContentValues values, @Nullable String where, // 検索条件(selectionと同じ) @Nullable String[] selectionArgs // 検索条件の値 ) { ... }
public final int delete( @NonNull Uri url, @Nullable String where, // 検索条件(selectionと同じ) @Nullable String[] selectionArgs // 検索条件の値 ) { ... }
そして、絞り込みの条件は引数で指定します。
(1)projection引数は、アクセスするカラムを絞り込み ※queryのみ
(2)selection/selectionArgs引数は、カラム値が条件に合うメディア情報を絞り込み
(1)projection(queryのみ)
projectionへアクセス対象のカラム名をString配列で指定します。
queryにおいて、結果(Cursorオブジェクト)が指定したカラムに限定されます。
# pwd /data/data/com.android.providers.media/databases # sqlite3 ./external.db sqlite> .headers on sqlite> .mode column sqlite> select * from images; _id _data _size _display_name mime_type title date_added date_modified description picasa_id isprivate latitude longitude datetaken orientation mini_thumb_magic bucket_id bucket_display_name width height ---------- ---------------------------------------------- ---------- ----------------- ---------- ------------- ---------- ------------- ----------- ---------- ---------- ---------- ---------- ---------- ----------- ---------------- ----------- ------------------- ---------- ---------- 26 /storage/emulated/0/Pictures/1754872524603.jpg 1754872524603.jpg image/jpeg 1754872524603 1754872524 -1617409521 Pictures 27 /storage/emulated/0/DCIM/1754872524618.jpg 1754872524618.jpg image/jpeg 1754872524618 1754872524 -2075821635 DCIM 28 /storage/emulated/0/Pictures/1754872524622.png 1754872524622.png image/png 1754872524622 1754872524 -1617409521 Pictures 29 /storage/emulated/0/DCIM/1754872524628.png 1754872524628.png image/png 1754872524628 1754872524 -2075821635 DCIM
// val _projection = null // 取得するカラム(※1) val _projection = arrayOf( // 取得するカラム MediaStore.Images.Media._ID, MediaStore.Images.Media.DISPLAY_NAME ) val _selection = null // 検索条件 val _selectionArgs = null // 検索条件の値 val _sortOrder = null // ソート順 val _cursor = contentResolver.query( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, _projection, _selection, _selectionArgs, _sortOrder ) _cursor?.use { dumpCursor(it) }
Column names = [_id, _display_name] Media id = 26 Media id = 27 Media id = 28 Media id = 29
ちなみに、nullを指定(※1)すると、絞り込みは無効になり、すべてのカラムがアクセス対象になります。
Column names = [_id, _data, _size, _display_name, mime_type, title, date_added, date_modified, description, picasa_id, isprivate, latitude, longitude, datetaken, orientation, mini_thumb_magic, bucket_id, bucket_display_name, width, height] Media id = 26 Media id = 27 Media id = 28 Media id = 29
(2)selection/selectionArgs
カラム値が条件に合うロウ(メディア情報)をアクセス対象にします。SQLの「WHERE句」と同じです。
selectionへ条件式を指定します。この条件式に「?」があると、「?」はselectArgsの値に置き換わります。
selectArgsは条件値をString配列で指定します。
- 左から1番目の「?」 ← selectArgsの[0]
- 左から2番目の「?」 ← selectArgsの[1]
- 左から3番目の「?」 ← selectArgsの[2]
- …
# pwd /data/data/com.android.providers.media/databases # sqlite3 ./external.db sqlite> .headers on sqlite> .mode column sqlite> select _id,_display_name,mime_type from images; _id _display_name mime_type ---------- ----------------- ---------- 26 1754872524603.jpg image/jpeg 27 1754872524618.jpg image/jpeg 28 1754872524622.png image/png 29 1754872524628.png image/png
val _projection = null // 取得するカラム // val _selection = null // 検索条件(※2) // val _selectionArgs = null // 検索条件の値 val _selection = "${MediaStore.Images.Media.MIME_TYPE}=?" val _selectionArgs = arrayOf( "image/png" ) val _sortOrder = null // ソート順 val _cursor = contentResolver.query( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, _projection, _selection, _selectionArgs, _sortOrder ) _cursor?.use { dumpCursor(it) }
Column names = [_id, _data, _size, _display_name, mime_type, title, date_added, date_modified, description, picasa_id, isprivate, latitude, longitude, datetaken, orientation, mini_thumb_magic, bucket_id, bucket_display_name, width, height] Media id = 28 ... PNG Media id = 29
ちなみに、nullを指定(※2)すると、絞り込みは無効になり、すべてのロウ(メディア情報)がアクセス対象になります。
Column names = [_id, _data, _size, _display_name, mime_type, title, date_added, date_modified, description, picasa_id, isprivate, latitude, longitude, datetaken, orientation, mini_thumb_magic, bucket_id, bucket_display_name, width, height] Media id = 26 ... JPEG Media id = 27 Media id = 28 ... PNG Media id = 29
例:id(複数)を持つメディア情報
複数のidを指定し、そのidを持つメディア情報へ絞り込む例です。
複数の条件式を「or」で連結することも出来ますが、idの個数が可変なら「in」の利用が得策です。
sqlite> select _id,_display_name,mime_type from images; _id _display_name mime_type ---------- ----------------- ---------- 26 1754872524603.jpg image/jpeg 27 1754872524618.jpg image/jpeg 28 1754872524622.png image/png 29 1754872524628.png image/png 30 1754879401184.jpg image/jpeg 31 1754879401204.jpg image/jpeg 32 1754879401210.png image/png 33 1754879401215.png image/png
val _ids = "'27','29','32'" // id(複数) val _projection = null // 取得するカラム val _selection = "${MediaStore.Images.Media._ID} in (${_ids})" val _selectionArgs = null val _sortOrder = null // ソート順 val _cursor = contentResolver.query( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, _projection, _selection, _selectionArgs, _sortOrder ) _cursor?.use { dumpCursor(it) }
Column names = [_id, _data, _size, _display_name, mime_type, title, date_added, date_modified, description, picasa_id, isprivate, latitude, longitude, datetaken, orientation, mini_thumb_magic, bucket_id, bucket_display_name, width, height] Media id = 27 Media id = 29 Media id = 32
例:nullを持つメディア情報
SQLiteにおいて、値が未指定のフィールドはnullです。
nullを持つメディア情報へ絞り込む例です。
sqlite> select _id,_display_name,mime_type,isprivate from images; _id _display_name mime_type isprivate ---------- ----------------- ---------- ---------- 26 1754872524603.jpg image/jpeg ... isprivate:null 27 1754872524618.jpg image/jpeg 0 ... ispribate:false 28 1754872524622.png image/png 29 1754872524628.png image/png 30 1754879401184.jpg image/jpeg 0 31 1754879401204.jpg image/jpeg 0 32 1754879401210.png image/png 33 1754879401215.png image/png 0 ※isprivateはBoolean、0:false/1:true(正しくは>0)
val _projection = null // 取得するカラム val _selection = "${MediaStore.Images.Media.IS_PRIVATE} is null" val _selectionArgs = null val _sortOrder = null // ソート順 val _cursor = contentResolver.query( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, _projection, _selection, _selectionArgs, _sortOrder ) _cursor?.use { dumpCursor(it) }
Column names = [_id, _data, _size, _display_name, mime_type, title, date_added, date_modified, description, picasa_id, isprivate, latitude, longitude, datetaken, orientation, mini_thumb_magic, bucket_id, bucket_display_name, width, height] Media id = 26 Media id = 28 Media id = 29 Media id = 32
例:範囲内のメディア情報
昨日追加されたメディア情報へ絞り込む例です。
上限と下限の条件式をandを用いて連結しています。上限の境界を「<」にするためです。
範囲の指定に「between」も利用可能ですが、境界が「下限≦x≦上限」になってしまいます。
sqlite> select _id,_display_name,date_added from images; _id _display_name date_added ---------- ----------------- ---------- 26 1754809710812.jpg 1754809710 ... '25/08/10(Yesterday) 27 1754809710882.jpg 1754809710 28 1754809710888.png 1754809710 29 1754809710892.png 1754809710 30 1754896131558.jpg 1754896131 ... '25/08/11(Today) 31 1754896131565.jpg 1754896131 32 1754896131570.png 1754896131 33 1754896131578.png 1754896131
val _dayBefore = calcDayBefore() val _start = _dayBefore.first val _end = _dayBefore.second val _projection = null // 取得するカラム val _selection = "${MediaStore.Images.Media.DATE_ADDED}>=? and ${MediaStore.MediaColumns.DATE_ADDED}<?" val _selectionArgs = arrayOf( _start.toString(), _end.toString() ) val _sortOrder = null // ソート順 val _cursor = contentResolver.query( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, _projection, _selection, _selectionArgs, _sortOrder ) _cursor?.use { dumpCursor(it) }
Column names = [_id, _data, _size, _display_name, mime_type, title, date_added, date_modified, description, picasa_id, isprivate, latitude, longitude, datetaken, orientation, mini_thumb_magic, bucket_id, bucket_display_name, width, height] Media id = 26 Media id = 27 Media id = 28 Media id = 29
Appendix:並び替え(sortOrder、queryのみ)
queryにおいて、sortOrderで結果の並び替えが行えます。SQLの「ORDER BY句」と同じです。
sqlite> select _id,_display_name,date_added from images; _id _display_name date_added ---------- ----------------- ---------- 26 1754899102809.jpg 1754899102 27 1754553524108.jpg 1754553524 28 1754639949043.jpg 1754639949 29 1754380767668.jpg 1754380767 30 1754899187882.jpg 1754899187
val _projection = null // 取得するカラム val _selection = null // 検索条件 val _selectionArgs = null // 検索条件の値 val _sortOrder = null // ソート順 // val _sortOrder = MediaStore.MediaColumns.DATE_ADDED // val _sortOrder = "${MediaStore.MediaColumns.DATE_ADDED} ASC" // val _sortOrder = "${MediaStore.MediaColumns.DATE_ADDED} DESC" val _cursor = contentResolver.query( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, _projection, _selection, _selectionArgs, _sortOrder ) _cursor?.use { dumpCursor(it) }
null
プライマリーキー(サンプルは_id)をソート対象にして、昇順に並び替えます。
Column names = [_id, _data, _size, _display_name, mime_type, title, date_added, date_modified, description, picasa_id, isprivate, latitude, longitude, datetaken, orientation, mini_thumb_magic, bucket_id, bucket_display_name, width, height] Media id = 26 Media id = 27 Media id = 28 Media id = 29 Media id = 30
カラム指定+ASC(昇順、デフォルト)
指定したカラム値をソート対象にして、昇順に並び替えます。
ASCはデフォルトです。「指定なし」はASCになります。
Column names = [_id, _data, _size, _display_name, mime_type, title, date_added, date_modified, description, picasa_id, isprivate, latitude, longitude, datetaken, orientation, mini_thumb_magic, bucket_id, bucket_display_name, width, height] Media id = 29 Media id = 27 Media id = 28 Media id = 26 Media id = 30
カラム指定+DESC(降順)
指定したカラム値をソート対象にして、降順に並び替えます。
Column names = [_id, _data, _size, _display_name, mime_type, title, date_added, date_modified, description, picasa_id, isprivate, latitude, longitude, datetaken, orientation, mini_thumb_magic, bucket_id, bucket_display_name, width, height] Media id = 30 Media id = 26 Media id = 28 Media id = 27 Media id = 29
関連記事: