スマホ内で共有されるMediaStorageにアクセスして画像や音楽ファイルをContentProviderを使って探してみます。
2021.2.1
ContentProvider
ContentProviderは外部アプリに対しテーブルに似たものとしてデータを提供するものです。
Ref: コンテンツ プロバイダの基本
コンテンツ プロバイダ
コンテンツ プロバイダにアクセスする一般的なパターンは、以下のようになります。
- CursorLoader を使用してバックグラウンドで非同期クエリを実行
- UI の Activity/Fragment は、クエリに対して CursorLoader を呼び出し
- ContentResolver を使用して ContentProvider からデータを取得
Ref: コンテンツ プロバイダの基本
ContentResolver.query() を呼び出してデータ情報を取得。
1 2 3 4 5 6 7 8 |
ContentResolver contentResolver = getContentResolver(); Cursor cursor = getContentResolver().query( Uri, // Uri of the table projection, // The columns to return for each row selection, // Selection criteria selectionArgs, // Selection criteria sortOrder); // The sort order for the returned rows |
Uri: DataBaseでのtable_nameに相当
例えば、画像であれば
MediaStore.Images.Media.EXTERNAL_CONTENT_URI
を渡します。これは
content://media/external/images/media
でありここを検索していくことになります。
projection: DataBaseでのcolumnであり、データの種類
例えば画像では以下のようなcolumnがあります
- MediaStore.Images.Media._ID
- MediaStore.Images.Media.DATA
- MediaStore.Images.Media.DISPLAY_NAME
- MediaStore.Images.Media.TITLE
- MediaStore.Images.Media.DATE_TAKEN
- MediaStore.Images.Media.DATE_ADDED
selection:
DataBaseのWHEREキーワードと同じ
selectionArgs: Selectionと一緒に使用される
selectionの疑問符(?)に入る内容がSelection args、argsの型は String[]
sortOrder: クエリ結果の行が表示される順序を指定
タイムスタンプで昇順・降順に分けるなど
Permissions
ContentProviderを使ってスマホ内のMediaStre内を検索しますのでPermissionが必要になります。
AndroidManifest.xmlに追加
1 |
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> |
READ_EXTERNAL_STORAGE は Runtime Permission に該当するため、アプリ起動中に許可を得るように設定します。
サンプルコード
端末内のMediaStorageにある画像を検索してみます。
最初に読み出し許可の処理を行います。
MainActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
//package your.package.name; import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts; import androidx.appcompat.app.AppCompatActivity; import android.Manifest; import android.annotation.SuppressLint; import android.content.ContentResolver; import android.content.pm.PackageManager; import android.database.Cursor; import android.os.Bundle; import android.provider.MediaStore; import android.widget.TextView; import android.widget.Toast; public class MainActivity extends AppCompatActivity { private final ActivityResultLauncher<String> requestPermissionLauncher = registerForActivityResult( new ActivityResultContracts.RequestPermission(), isGranted -> { if (isGranted) { readContent(); } else { // それでも拒否された時の対応 Toast toast = Toast.makeText(this, "これ以上なにもできません", Toast.LENGTH_SHORT); toast.show(); } }); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if (checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED) { requestPermissionLauncher.launch( Manifest.permission.READ_EXTERNAL_STORAGE); } else{ readContent(); } } @SuppressLint("Range") private void readContent(){ TextView textView = findViewById(R.id.text_view); ContentResolver contentResolver = getContentResolver(); Cursor cursor = null; StringBuilder sb = null; // 例外を受け取る try { cursor = contentResolver.query( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null,null,null,null); if (cursor != null && cursor.moveToFirst()) { String str = String.format( "MediaStore.Images = %s\n\n", cursor.getCount() ); sb = new StringBuilder(str); do { sb.append("ID: "); sb.append(cursor.getString(cursor.getColumnIndex( MediaStore.Images.Media._ID))); sb.append("\n"); sb.append("Title: "); sb.append(cursor.getString(cursor.getColumnIndex( MediaStore.Images.Media.TITLE))); sb.append("\n"); sb.append("Path: "); sb.append(cursor.getString(cursor.getColumnIndex( MediaStore.Images.Media.DATA))); sb.append("\n\n"); } while (cursor.moveToNext()); cursor.close(); } } catch (Exception e) { e.printStackTrace(); } finally{ if(cursor != null){ cursor.close(); } } textView.setText(sb); } } |
actiity_main.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<?xml version="1.0" encoding="utf-8"?> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#dfe" android:padding="5dp" tools:context=".MainActivity"> <TextView android:id="@+id/text_view" android:textColor="#000" android:textSize="20sp" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </ScrollView> |
READ_EXTERNAL_STORAGE とReadContentのAcitivtyを追加
AndroidManifest.xml
1 2 3 4 5 6 7 8 9 10 11 |
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" ... <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <application ... </application> </manifest> |
実行するとリストが表示されます。
Audio:
音楽ファイルを探すときは、 MediaStore.Images…をMediaStore.Audio.Media.EXTERNAL_CONTENT_URI
に変更すると検索できます。
Video:
動画の場合は、同様にテーブルを MediaStore.Video.Media.EXTERNAL_CONTENT_URI に変えると確認できます。
実際にemulatorがどうなっているかはDevice File Explorerを使うと確認できます。
関連ページ:
Reference:
コンテンツ プロバイダの基本
共有ストレージからメディア ファイルにアクセスする