Intentを使って複数枚画像を取得するときのメモ
Intentを使ってPhotoとかいい感じの(=ユーザが選択した)アプリから画像を選択したいときに、1枚なのか複数枚なのかで色々違うのでメモ。
複数枚画像を選択する場合
選択させるアプリを起動するとき
ポイントは Intent.EXTRA_ALLOW_MULTIPLE
のextraをtrueに設定すること。
色々ググったときにactionが Intent.ACTION_GET_CONTENT
でいけると書いていたけど、これだと複数画像選択できず一枚選択した時点で元のアプリに戻ってしまう挙動になった。(OS 7.1.2/Nexus 6P実機環境)
下記コードのように Intent.ACTION_PICK
だと動く。
val intent = Intent() intent.type = "image/*" intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true) intent.action = Intent.ACTION_PICK this.startActivityForResult(Intent.createChooser(intent, "Choose Photo"), CHOOSE_PHOTO_REQUEST_CODE)
選択した画像の情報を取り出すとき
Activity#onActivityResult()
で受け取るintentの clipData
にuriの情報が入っているのでこれを使う。
下記のサンプルコードは選択した画像のuriの情報を取り出してlistViewに表示するコードの一部。 getItemAt()
で各要素にアクセスできる。
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == CHOOSE_PHOTO_REQUEST_CODE && resultCode == Activity.RESULT_OK) { val itemCount = data?.clipData?.itemCount ?: 0 val uriList = mutableListOf<Uri>() for (i in 0..itemCount - 1) { val uri = data?.clipData?.getItemAt(i)?.uri uri?.let { uriList.add(it) } } this.adapter.data = uriList this.adapter.notifyDataSetChanged() } }
余談だけど、 clipData
が保持しているuriの情報を持っているArrayListがpublicではない、かつ直接アクセスするためのAPIが公開されていないのでこんな汚い感じでmutableListだったりfor文だったりを使わないといけない感じになった(´;ω;`)
↓ClipDataのコード
Cross Reference: /frameworks/base/core/java/android/content/ClipData.java
153 public class ClipData implements Parcelable { 167 final ArrayList<Item> mItems; // publicじゃない 819 /** 820 * Return a single item inside of the clip data. The index can range 821 * from 0 to {@link #getItemCount()}-1. 822 */ 823 public Item getItemAt(int index) { 824 return mItems.get(index); // 指定したindexの要素しか取れない 825 }
もしimmutableなmItemsがgetできたり別のiterableな何かが取得できるAPIが生えてたら、こんな感じでもっと綺麗にかけるのに…
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == CHOOSE_PHOTO_REQUEST_CODE && resultCode == Activity.RESULT_OK) { // もしmItemsに外部からアクセスできたらこんな感じで1行で済ませられそう this.adapter.data = data?.clipData?.items.map { it.uri } ?: emptyList() this.adapter.notifyDataSetChanged() } }
拡張関数とか自分で書いてもいいけど、そんなに利用頻度高くなさそう、ということで諦めてしまいそう。
1枚だけ画像を選択する場合
選択させるアプリを起動するとき
この場合のactionは Intent.ACTION_GET_CONTENT
でいけた。
val intent = Intent() intent.type = "image/*" intent.action = Intent.ACTION_GET_CONTENT this.startActivityForResult(Intent.createChooser(intent, "Choose Photo"), CHOOSE_PHOTO_REQUEST_CODE)
選択した画像の情報を取り出すとき
取り出すときは複数枚の場合と同じく、Activity#onActivityResult()
で受け取るintentの clipData
にuriの情報が入っているので同様に扱うことができる。