Androidでファイル選択をするときは、
ACTION_OPEN_DOCUMENT
というのが使えます。
これを使うと端末内の画像とかファイルが選択可能。
ただデフォルトでは単体選択なので、
複数画像(ファイル)を選択する方法をまとめました。
ではその手順を早速紹介していきます。
コード例と一緒にまとめると次の通りです。
1.複数選択可なIntentを起動させる
まずはIntentの起動から
このようなコードで複数選択可にできました。
▼ 複数選択できるIntenteの起動例
1 2 3 4 5 6 7 |
Intent intent = new Intent(); intent.setType("image/*"); intent.setAction(Intent.ACTION_OPEN_DOCUMENT); intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true); String title = "Select multiple images"; Intent chooser = Intent.createChooser(intent, title); startActivityForResult(chooser, REQ_CODE_CHOOSE_FILES_URI); |
大事なポイントは次の2つ
- ACTION_OPEN_DOCUMENT を使うこと
Android 4.4 以降から使用可能。このアクションを指定するとシステム制御のピッカーUIを起動できる。もしAndroid4.3以下にも対応させたいなら ACTION_PICK など使わないとダメらしい
- EXTRA_ALLOW_MULTIPLE を指定する事
上コードの intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true); の部分。この指定をしておくだけで複数画像など複数ファイル選択が可能に。
あと REQ_CODE_CHOOSE_FILES_URI はActivity内に宣言した定数です。これを onActivityReusult を受け取るときに使うので、好きな名前で宣言・変更しておいてください。
あと複数画像なのでMIMEタイプも設定してます。(任意)
起動するUIピッカーの見た目はこんな感じ。
▲ 端末は Android7.0 Glaxy を使用
ファイル長押しで複数選択できました。
それ以外は単体選択と全く変わりません。
2.onActivityResultから複数画像を受け取る
ピッカーが起動したら onActivityResult で結果受け取り
複数選択では ClipData に複数ファイル情報が入ります。
▼ ClipDataとは何か?公式リファレンスでの説明
Representation of a clipped data on the clipboard.
ClipData is a complex type containing one or more Item instances, each of which can hold one or more representations of an item of data. For display to the user, it also has a label.
▼ この説明の簡単な意訳
クリップボード上のクリップデータを表す。
ClipDataは1つ以上の ClipData.Item インスタンスを持つ複雑型で、それぞれは1つ以上のデータ表現を持ってます。ユーザーに分かりやすく表示するためにラベルも持ってます。
元々はクリップボードのデータを格納するもの。
どうやら ACTION_OPEN_DOCUMENT のようなファイル選択ピッカーを起動したときにも、そのファイル情報(URI, MIMEタイプ)を受け取りにも使われるようです。
実際の onActivityResult のコードはこういう感じです。
▼ こういうコードを書いてみた
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 |
@Override public void onActivityResult(int requestCode, int resultCode, Intent intent) { super.onActivityResult(requestCode, resultCode, intent); switch(requestCode) { case REQ_CODE_CHOOSE_FILES_URI: { if (intent == null) { break; } Uri uri = intent.getData(); List<String> filePaths = new ArrayList<String>(); if (intent.getData() != null) { filePaths.add(intent.getData().toString()); } else { ClipData clipData = intent.getClipData(); int clipItemCount = clipData.getItemCount(); for (int i = 0; i < clipItemCount; i++) { ClipData.Item item = clipData.getItemAt(i); Uri itemUri = (item != null) ? item.getUri() : null; final int modeFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION; getContentResolver() .takePersistableUriPermission(itemUri, modeFlags); filePaths.add(itemUri.toString()); } } /// 選択画像でゴニョゴニョ... break; } } } |
このコードで重要なポイントは次の2点
- ClipDataから受け取り
1つのファイルURIは ClipData.Item から受け取り可能。上コードのようにループを回し、 clipData.getItemAt(i); みたいに1つ1つのファイル情報が受け取れる
- 単体ファイルの処理を分ける
もし選択が複数ではなく1つだけなら、 intent.getData().toString() のように ClipData を使わずにアクセスできる。
あと本筋とは関係ないんですが、端末再起動するまでの永続的なアクセスが必要なら getContentResolver().takePersistableUriPermission(itemUri, modeFlags); のように許可を取ればOKです。
もしコードで間違いがある場合はご指摘ください。
以上、Intentでの複数画像選択でした。ではまた($・・)/~~~