概要
AdapterからのstartActivityForResult()呼び出しとonActivityResult()での結果受け取りが動作しなかった時の対応方法のメモです。
環境
Kotlin 1.5.21
Android Studio Arctic Fox 2020.3.1
macOS Big Sur 11.4
実装
標準ギャラリーの起動と選択結果の受け取りは以下のような実装をよく見かけますが、この実装だとAdapter内で選択結果を受け取ることができません。
またこの方法は非推奨になっています。
private fun selectPhoto() {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
type = "image/*"
}
startActivityForResult(intent, READ_REQUEST_CODE)
}
companion object {
private const val READ_REQUEST_CODE: Int = 42
}
override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
super.onActivityResult(requestCode, resultCode, resultData)
if (resultCode != RESULT_OK) {
return
}
when (requestCode) {
READ_REQUEST_CODE -> {
resultData?.data?.also { uri ->
// ImageView表示処理...
}
}
}
}
ではAdapter内で選択結果を受け取るにはどうすれば良いかというと、registerForActivityResult()を使用します。
まずはアプリレベルのbuild.gradleに以下を追記します。
今回はfragmentで実装したのでactivityはコメントアウトしてあります。
// implementation 'androidx.activity:activity-ktx:1.4.0-alpha02'
implementation 'androidx.fragment:fragment-ktx:1.4.0-alpha09'
次に結果のコールバックを登録するためのregisterForActivityResult()を使用します。
val launcher = registerForActivityResult(ActivityResultContracts.OpenDocument()) {
// 結果を受け取る
}
registerForActivityResult()はActivityResultLauncherを返すのでAdapterに渡して起動します。
setOnClickListener { _launcher.launch(arrayOf("image/*")) }
全体はこんな感じです。
class SampleFragment() : Fragment() {
@SuppressLint("InflateParams")
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val v: View = inflater.inflate(R.layout.sample_fragment, null)
val launcher = registerForActivityResult(ActivityResultContracts.OpenDocument()) {
// アクティビティ(標準ギャラリー)の結果受け取り
Log.d("Uri", it.toString())
}
val myAdapter = context?.let {
MyAdapter(
inflater,
listOf("sample1","sample2"),
launcher,
)
}
v.findViewById(R.id.listView).apply {
adapter = myAdapter
}
return v
}
class MyAdapter(
private val _inflater: LayoutInflater,
private val _list: List,
private var _launcher: ActivityResultLauncher>,
) : BaseAdapter() {
override fun getCount(): Int {
return _list.count()
}
override fun getItem(i: Int): Any? {
return _list[i]
}
override fun getItemId(i: Int): Long {
return i.toLong()
}
@SuppressLint("ViewHolder", "InflateParams")
override fun getView(i: Int, convertView: View?, parent: ViewGroup?): View {
return _inflater.inflate(R.layout.sample_row, null).also {
it.findViewById(R.id.sample_image).apply {
// アクティビティ(標準ギャラリー)の起動
setOnClickListener { _launcher.launch(arrayOf("image/*")) }
}
}
}
}
}