【Android】画像を選択して、ImageViewに表示 in Kotlin

# ➊ はじめに
「`画像を選択して、ImageViewに表示する方法`」として「**startActivityForResult** と **onActivityResult**」で実装していたのですが、Androidは日進月歩しているらしく、この方法で実装するのは`非推奨`になってしまいました。

> 基盤となる startActivityForResult() API と onActivityResult() API はあらゆる API レベルの Activity クラスで使用できますが、AndroidX Activity と Fragment で導入された Activity Result API を使用することを強くおすすめします。

とのことなので、推奨方法をここ👉「[`アクティビティの結果を取得する`](https://developer.android.com/training/basics/intents/result)」で調べつつ、実装してみたいと思います。

# ➋ どんな感じ？
百聞は一見にしかずということで、こんな感じ～になります。
「`SELECT IMAGE`」ボタンを押下すると、カメラで撮った画像を選択するアクティビティに切り替わります。画像を選択すると、選択した画像がアプリの**ImageView**に表示されます。

<img width=240" src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405376/09e599a5-baeb-e005-b547-f9072e5050aa.gif'>

# ➌ お勉強ポイント
- ギャラリーアクティビティの起動
- アクティビティ結果の受け取り

※推奨されている「AndroidX Activity と Fragment で導入された Activity Result API」を使用。

# ➍ アクティビティの起動と結果取得
## (1) アクティビティの結果に対するコールバックの登録
- アクティビティ結果のコールバックを登録するため、**registerForActivityResult()**を用います。
- **StartActivityForResult**コントラクトは、任意のIntentを入力として受け取ってActivityResultを返す汎用コントラクトです。このコントラクトを使用すると、コールバックの一部としてresultCodeとIntentを抽出できます。

``` kotlin:snippet
    // アクティビティの結果に対するコールバックの登録
    private val launcher = registerForActivityResult(
        ActivityResultContracts.StartActivityForResult()
    ) { result ->
        Log.d("registerForActivityResult(result)", result.toString())

        if (result.resultCode != RESULT_OK) {
            // アクティビティ結果NG 
        } else {
            // アクティビティ結果OK
            // ・・・
        }
    }
```
※アクティビティの結果関連の詳細ドキュメントは、こちら👉「[アクティビティの結果を取得する](https://developer.android.com/training/basics/intents/result)」をご参照ください。

## (2) アクティビティの起動
- **launch()**でアクティビティ(画像選択画面)を起動します。

``` kotlin:snippet
        val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
            addCategory(Intent.CATEGORY_OPENABLE)
            type = "image/*"
        }
        launcher.launch(intent)
```
※インテント関連の詳細ドキュメントは、こちら👉「[ファイル ストレージ](https://developer.android.com/guide/components/intents-common?hl=ja#Storage)」をご参照ください。

# ➎ 実装
仕組みが分かったところで、上記をまとめ、諸々実装していきます。
言語は、「**Kotlin**」で実装します。

## (1) activity_main.xml
> app/src/main/res/layout/activity_main.xml

UIはこんな感じになります。
<img width="800" src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405376/46b4178e-3872-0a3a-7d9b-8d9253f99958.png'>

コードはこちら。

``` xml:activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">


    <ImageView
        android:id="@+id/imageView"
        android:layout_width="409dp"
        android:layout_height="260dp"
        android:contentDescription="image view"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.161" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Select Image"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.498"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.814" />

</androidx.constraintlayout.widget.ConstraintLayout>
```

## (2) MainActivity.kt
> app/src/main/java/com/poodlemaster/app4/MainActivity.kt

```kotlin:MainActivity.kt
package com.poodlemaster.app4

import android.content.Intent
import android.graphics.BitmapFactory
import androidx.appcompat.app.AppCompatActivity
import android.net.Uri
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.Toast
import android.widget.Button
import android.widget.ImageView
import androidx.activity.result.contract.ActivityResultContracts

class MainActivity : AppCompatActivity(), View.OnClickListener {

    //-------------------------------------------------------------------------
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Log.d("status", "onCreate")
        setContentView(R.layout.activity_main)

        val button: Button = findViewById(R.id.button)
        button.setOnClickListener(this)
    }

    //-------------------------------------------------------------------------
    override fun onClick(view: View){
        when (view.id) {
            R.id.button -> {
                selectPhoto()
            }
        }
    }

    //-------------------------------------------------------------------------
    private val launcher = registerForActivityResult(
        ActivityResultContracts.StartActivityForResult()
    ) { result ->
        Log.d("registerForActivityResult(result)", result.toString())

        if (result.resultCode != RESULT_OK) {
            return@registerForActivityResult
        } else {
            try {
                result.data?.data?.also { uri : Uri ->
                    val inputStream = contentResolver?.openInputStream(uri)
                    val image = BitmapFactory.decodeStream(inputStream)
                    val imageView: ImageView = findViewById(R.id.imageView)
                    imageView.setImageBitmap(image)
                }
            } catch (e: Exception) {
                Toast.makeText(this, "エラーが発生しました", Toast.LENGTH_LONG).show()
            }
        }
    }

    //-------------------------------------------------------------------------
    private fun selectPhoto() {
        val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
            addCategory(Intent.CATEGORY_OPENABLE)
            type = "image/*"
        }
        launcher.launch(intent)
    }
}
```

# ➏ 以上
最近、Androidアプリの基礎を勉強してみようと、重い腰を上げようやく「**Android Studio**」をインストールしました。kotlinという言語も初めて使いました。JAVAも触ったことなかったので、まずは見様見真似と自己流改造で色々と学べたらと思っています。

お疲れ様でした😊