[Android] 様々なアクティビティーの作り方における、RegisterForActivityResultの使い方


# １．概要
　startActivityForResultが非推奨になり、その代替えとしてregisterForActivityResultが推奨されたので、[様々なアクティビティー](https://qiita.com/guijiu/items/9b6c3d0b9a13117d8c08#%EF%BC%94%E6%A7%98%E3%80%85%E3%81%AA%E3%82%A2%E3%82%AF%E3%83%86%E3%82%A3%E3%83%93%E3%83%86%E3%82%A3%E3%81%AE%E4%BD%9C%E3%82%8A%E6%96%B9%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8Bregisuterforactivityresult%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9)の作り方ごとに、その使い方を具体的にまとめた。


# ２．参考資料(ホームページアドレスや書籍)
　本記事を作成するにあたり、次のサイトとリポジトリを参考にした。
　　　　・[AndroidのstartActivityForResultに変わる新しいAPIが追加されました](https://dev.classmethod.jp/articles/androidx-startactivityforresult/)
　　　　・[Android デベロッパードキュメントガイド　](https://developer.android.com/training/basics/intents/result)

　　　　・[startActivityForResult / requestPermissions が deprecated になる話](https://qiita.com/m-coder/items/97a3ce16276334be84aa)
　　　　・https://github.com/nanaten/Activity[-Contract-Example
　　　　・[掌田著 Android Jetpackプログラミング](https://www.shuwasystem.co.jp/book/9784798063218.html)
　　　　・[金田著 はじめてのAndroidプログラミング（第４版、第５版）](https://www.sbcr.jp/product/4815607968/)
　　　　・[山田著 Androidアプリ開発（第３版）](https://wings.msn.to/index.php/-/A-03/978-4-7980-5759-0/)
　　　　・[斎藤著 Androidアプリ開発の教科書Kotlin対応（初版）]()


# ３．registerForActivityResultを使う上で必ず行うべきこと
　registerForActivityResultを使うためには、必ずbuild.gradleに以下を追加する。（ただし、今回はFragmentを使わないので、fragmet-ktxの方は追加しなくてもよい。）

```gradle:build.gradle(app)
dependencies {
    //  (省略)
    implementation "androidx.activity:activity-ktx:1.2.0-alpha04"
    implementation "androidx.fragment:fragment-ktx:1.3.0-alpha03"
    //  (省略)
}
```

# ４．様々なアクティビティの作り方におけるregisuterForActivityResultの使い方
　次の６つのアクティビティの作り方で、regisuterForActivityResultの使い方の使い方を試した。
　　　　ver.01 レイアウトUIへのアクセスにfindView()でViewのインスタンスを生成し、
　　　　　　　リスナークラスをインナークラスで作る方法
　　　　ver.02 リスナークラスをObject式を用いて記述して作る方法
　　　　ver.03 リスナークラスのonClick関数をレイアウトファイルのonClick属性に設定する方法
　　　　ver.04 レイアウトUIへのアクセスに、Kotlin-Android-Extensions(KAE)を利用し、
　　　　　　　setOnClickListenerにSAM変換方法を用いる方法
　　　　ver.05 レイアウトUIへのアクセスに、ViewBindingを用いる方法
　　　　ver.06 レイアウトUIへのアクセスに、DataBindingを用いる方法
　
　なお、レイアウトファイルは基本的に次のファイルを使い、ver.03のレイアウトファイルのonClick属性のバージョンとver.06のDataBindingのバージョンについては、適宜変更を行う。

基本的なレイアウトファイル：

```activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <Button
        android:id="@+id/btnMain"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="サブ画面へ">
    </Button>
</LinearLayout>
```

```activity_sub.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <EditText
        android:id="@+id/etMessage"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:inputType="text">
    </EditText>
    <Button
        android:id="@+id/btnBack"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="メイン画面へ" >
    </Button>
</LinearLayout>
```

　以上のレイアウトファイルを実行したときに表示される画面は以下の通り。
![Activity.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/501068/7bdd64c5-7020-4674-cf20-f4a504e20921.png)


## 4.1 レイアウトUIへのアクセスにfindView()でViewのインスタンスを生成し、リスナークラスをインナークラスで作る方法(ver.01)
```MianActivity.kt
class MainActivity : AppCompatActivity() {
    // registerForActivityResult を定義する
    val getContent =
        registerForActivityResult(StartActivityForResult()) { result: ActivityResult ->
            // 呼び出し先のActivityを閉じた時に呼び出されるコールバックを登録
            // (呼び出し先で埋め込んだデータを取り出して処理する)
            if (result.resultCode == Activity.RESULT_OK) {
                // RESULT_OK時の処理
                val resultIntent = result.data
                val message = resultIntent?.getStringExtra("message")
                Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
            }
        }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // registerForActivityResult を定義する
        val btnMain = findViewById<Button>(R.id.btnMain)


        // ボタンをタップした時の処理
        val listener = BtnSendListener()
        btnMain.setOnClickListener(listener)
    }

    // リスナークラス
    private inner class BtnSendListener : View.OnClickListener {
        override fun onClick(v: View?) {
            // registerForActivityResult を定義する
            val requestIntent = Intent(applicationContext, SubActivity::class.java)
            // SubActivityを起動
            getContent.launch(requestIntent)
        }
    }
}
```


```SubActivity.kt
class SubActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_sub)

        val btnBack = findViewById<Button>(R.id.btnBack)
        val listener = BtnBackSendListener()
        btnBack.setOnClickListener(listener)
    }

    // リスナークラス
    private inner class BtnBackSendListener : View.OnClickListener {
        override fun onClick(v: View?) {
            val etMessage: EditText = findViewById(R.id.etMessage)
            // インテントにetMessageのtextをセット
            intent.putExtra("message", etMessage.text.toString())
            // 結果をセット
            setResult(Activity.RESULT_OK, intent)
            finish()
        }
    }
}
```
 
## 4.2 リスナークラスをObject式を用いて記述して作る方法(ver.02)
```MianActivity.kt
class MainActivity : AppCompatActivity() {
    val getContent =
        registerForActivityResult(StartActivityForResult()) { result: ActivityResult ->
            // 呼び出し先のActivityを閉じた時に呼び出されるコールバック
            if (result.resultCode == Activity.RESULT_OK) {
                // RESULT_OK時の処理
                val resultIntent = result.data
                val message = resultIntent?.getStringExtra("message")
                Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
            }
        }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val btnMain = findViewById<Button>(R.id.btnMain)

        btnMain.setOnClickListener(
            object : View.OnClickListener {
                override fun onClick(v: View?) {
                    // registerForActivityResult を定義する
                    val requestIntent = Intent(applicationContext, SubActivity::class.java)
                    getContent.launch(requestIntent)
                }
            }
        )
    }
}
```

```SubActivity.kt
class SubActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_sub)

        val btnBack = findViewById<Button>(R.id.btnBack)

        btnBack.setOnClickListener(
            object: View.OnClickListener {
                override fun onClick(v: View?) {
                    val etMessage: EditText = findViewById(R.id.etMessage)
                    // インテントにetMessageのtextをセット
                    intent.putExtra("message", etMessage.text.toString())
                    // 結果をセット
                    setResult(Activity.RESULT_OK, intent)
                    finish()
                }
            }
        )
    }
}
```

 
## 4.3 リスナークラスのonClick関数をレイアウトファイルのonClick属性に設定する方法(ver.03)
```MianActivity.kt
class MainActivity : AppCompatActivity() {
    // registerForActivityResult を定義する
    val getContent =
        registerForActivityResult(StartActivityForResult()) { result ->
            // 呼び出し先のActivityを閉じた時に呼び出されるコールバック
            if (result.resultCode == Activity.RESULT_OK) {
                // RESULT_OK時の処理
                val resultIntent = result.data
                val message = resultIntent?.getStringExtra("message")
                Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
            }
        }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }

    // ボタンをタップした時の処理
    fun btnSend_onClick(v: View) {
        // registerForActivityResult を定義する
        val requestIntent = Intent(applicationContext, SubActivity::class.java)
        // SubActivityを起動
        getContent.launch(requestIntent)
    }
}

```

```SubActivity.kt
class SubActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_sub)
    }

    fun btnBack_onClick(v: View) {
        val etMessage: EditText= findViewById(R.id.etMessage)
        // インテントにetMessageのtextをセット
        intent.putExtra("message", etMessage.text.toString())
        // 結果をセット
        setResult(Activity.RESULT_OK, intent)
        finish()
    }
}
```

　また、setOnClickListener()メソッドの機能をレイアウトファイルに埋め込むためにonClick属性をレイアウトファイルに追記する。

```activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
        (省略)
    <Button
        android:id="@+id/btnMain"
            (省略)
        android:onClick="btnSend_onClick"    <--追記
        android:text="サブ画面へ">
    </Button>
</LinearLayout>
```


```activity_sub.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
        (省略)
    <Button
        android:id="@+id/btnBack"
            (省略)
        android:onClick="btnBack_onClick"    <--追記
        android:text="メイン画面へ" >
    </Button>
</LinearLayout>
```

## 4.4 レイアウトUIへのアクセスに、Kotlin-Android-Extensions(KAE)を利用し、setOnClickListenerにSAM変換方法を用いる方法(ver.04)
　KAEを利用するためには、先ずbuild.gradle(:app)のplugingsにKotlinアンドロイド拡張プラグインを追記する。


```build.gradle
plugins {
    id 'com.android.application'
    id 'kotlin-android'
    id 'kotlin-android-extensions'    // 追記
}
```

　またMainActivity.ktとSubActivity.ktは以下のとおり。但し、レイアウトファイルは基本レイアウトと同じである。

```MianActivity.kt
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {
    // registerForActivityResult を定義する
    val getContent =
        registerForActivityResult(StartActivityForResult()) { result: ActivityResult ->
            // 呼び出し先のActivityを閉じた時に呼び出されるコールバック
            if (result.resultCode == Activity.RESULT_OK) {
                val resultIntent = result.data
                val message = resultIntent?.getStringExtra("message")
                Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
            }
        }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // ボタンをタップした時の処理
        btnMain.setOnClickListener {
            val requestIntent = Intent(this, SubActivity::class.java)

            // SubActivityを起動
            getContent.launch(requestIntent)
        }
    }
}
```
 

```SubActivity.kt
import kotlinx.android.synthetic.main.activity_sub.*    // Kotlinアンドロイド拡張のためのインポート

class SubActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_sub)

        btnBack.setOnClickListener {
            // インテントにetMessageのtextをセット
            intent.putExtra("message", etMessage.text.toString())
            // 結果をセット
            setResult(Activity.RESULT_OK, intent)
            finish()
        }
    }
}
```

## 4.5 レイアウトUIへのアクセスに、ViewBindingを用いる方法(ver.05)
　以下のようにViewBingdingを利用するために、build.gradle(:app)のandoroi{……}の中にbuildFeatures{……}を追記し、ViewBindingを有効にする。

```build.gradle
android {
    compileSdkVersion 30
    buildToolsVersion "30.0.3"
        (省略)
    buildFeatures{              //追記
        viewBinding = true
    }
}
```

```MianActivity.kt
class MainActivity : AppCompatActivity() {
    // registerForActivityResult を定義する
    val getContent =
        registerForActivityResult(StartActivityForResult()) { result: ActivityResult ->
            // 呼び出し先のActivityを閉じた時に呼び出されるコールバック
            if (result.resultCode == Activity.RESULT_OK) {
                // RESULT_OK時の処理
                val resultIntent = result.data
                val message = resultIntent?.getStringExtra("message")
                Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
            }
        }

    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // ViewBindingを定義する
        binding = ActivityMainBinding.inflate(layoutInflater)
        val view = binding.root
        setContentView(view)

        // ボタンをタップした時の処理
        binding.btnMain.setOnClickListener {
            // registerForActivityResult を定義する
            val requestIntent = Intent(applicationContext, SubActivity::class.java)
            // SubActivityを起動
            getContent.launch(requestIntent)
        }
    }
}
```

```SubActivity.kt
class SubActivity : AppCompatActivity() {
    private lateinit var binding: ActivitySubBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = ActivitySubBinding.inflate(layoutInflater)
        val view = binding.root
        setContentView(view)

        binding.btnBack.setOnClickListener {
            // インテントにetMessageのtextをセット
            intent.putExtra("message", binding.etMessage.text.toString())
            // 結果をセット
            setResult(Activity.RESULT_OK, intent)
            finish()
        }
    }
}
```


##4.6 レイアウトUIへのアクセスに、DataBindingを用いる方法(ver.06)
　以下のようにDataBingdingを利用するために、build.gradle(:app)のandoroi{……}の中にbuildFeatures{……}を追記し、DataBindingを有効にする。

```build.gradle
android {
    compileSdkVersion 30
    buildToolsVersion "30.0.3"
        (省略)
    buildFeatures{              //追記
        DataBinding = true
    }
}
```


```MianActivity.kt
class MainActivity : AppCompatActivity() {
    // registerForActivityResult を定義する
    val getContent =
        registerForActivityResult(StartActivityForResult()) { result: ActivityResult ->
            // 呼び出し先のActivityを閉じた時に呼び出されるコールバック
            if (result.resultCode == Activity.RESULT_OK) {
                // RESULT_OK時の処理
                val resultIntent = result.data
                val message = resultIntent?.getStringExtra("message")
                Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
            }
        }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // dataBindingを定義する
        val binding: ActivityMainBinding = DataBindingUtil
            .setContentView(this, R.layout.activity_main)

        // ボタンをタップした時の処理
        binding.btnMain.setOnClickListener {
            // registerForActivityResult を定義する
            val requestIntent = Intent(applicationContext, SubActivity::class.java)
            // SubActivityを起動
            getContent.launch(requestIntent)
        }
    }
}

```

```SubActivity.kt
class SubActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // dataBindingを定義する
        val binding: ActivitySubBinding = DataBindingUtil
            .setContentView(this, R.layout.activity_sub)

        binding.btnBack.setOnClickListener{
            // インテントにetMessageのtextをセット
            intent.putExtra("message", binding.etMessage.text.toString())
            // 結果をセット
            setResult(Activity.RESULT_OK, intent)
            finish()
        }
    }
}
```