Smile Engineering Blog

ジェイエスピーからTipsや技術特集、プロジェクト物語を発信します

【Android】Activity Result API で他の Activity の結果を取得する

今回は、Activity Result API で他の Activity の結果を取得する方法を解説します。

なお、ここに掲載しているソースコードは以下の環境で動作確認しています。

  • Android Studio Chipmunk | 2021.2.1 Patch 1
  • JDK 11.0.12
  • Android Gradle Plugin 7.2.1
  • Kotlin 1.6.21
  • Gradle 7.4.2
  • androidx.activity 1.4.0
  • androidx.fragment 1.4.1

概要

以前、他の Activity の結果を取得する方法として、startActivityForResult と onActivityResult を使う方法がありました。しかし、現在この方法は非推奨になっており、代わりに Activity Result API を使う方法が推奨されています。

今回は、文字列を結果として返す Activity から Activity Result API でその結果を取得するサンプルの作成を通して、Activity Result API の使い方を解説します。

なお、Activity Result API は、ComponentActivity と Fragment の両方で使用することができるため、Activity と Fragment のそれぞれで解説します。

Activity で Activity Result API を使う

ライブラリのインポート

Activity で Activity Result API を使う場合、アプリの build.gradle ファイルの dependenciesactivity-ktx を追加してください。

dependencies {
    implementation "androidx.activity:activity-ktx:1.4.0"
}

他の Activity の結果を取得する

ここから、文字列を結果として返す Activity と、Activity Result API でその結果を取得する Activity を作成します。

まず、文字列を結果として返す Activity から作成します。

class SubActivity : AppCompatActivity(R.layout.sub_activity) {

    companion object {

        const val EXTRA_RESULT = "result"

        fun createIntent(context: Context) =
            Intent(context, SubActivity::class.java)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        findViewById<Button>(R.id.inputButton)
            .setOnClickListener {
                setResult(RESULT_OK, Intent().apply {
                    val editText: TextInputEditText =
                        findViewById(R.id.textInputEditText)
                    val text = editText.text.toString()
                    putExtra(EXTRA_RESULT, text)
                })
                finish()
            }
    }
}

この Activity には EditText と Button があり、Button が押されると EditText に入力された文字列を Activity の結果として返すようにします。

Activity の結果として返す際には、setResult に RESULT_OK と 返す文字列を格納した Intent を渡します。setResult を使って Activity の結果を返す方法は、startActivityForResult と onActivityResult を使っていたときと同じです。

次に、Activity Result API で他の Activity の結果を取得する Activity を作成します。

class MainActivity : AppCompatActivity(R.layout.main_activity) {

    private val subActivityLauncher = registerForActivityResult(
        ActivityResultContracts.StartActivityForResult()
    ) { result ->
        if (result.resultCode == RESULT_OK) {
            val text = result.data?.getStringExtra(SubActivity.EXTRA_RESULT) ?: ""
            findViewById<TextView>(R.id.resultTextView).text = text
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        findViewById<Button>(R.id.inputButton)
            .setOnClickListener {
                val intent = SubActivity.createIntent(this)
                subActivityLauncher.launch(intent)
            }
    }
}

Activity Result API を使う場合、まず registerForActivityResult を使って、他のアクティビティを開始するために使用する ActivityResultLauncher を取得します。

この registerForActivityResult には、他のアクティビティから結果を取得することを表す ActivityResultContracts.StartActivityForResult() を渡します。そして、結果を取得した後に呼び出されるコールバックも渡します。

    private val subActivityLauncher = registerForActivityResult(
        ActivityResultContracts.StartActivityForResult()
    ) { result ->
        if (result.resultCode == RESULT_OK) {
            val text = result.data?.getStringExtra(SubActivity.EXTRA_RESULT) ?: ""
            findViewById<TextView>(R.id.resultTextView).text = text
        }
    }

そして、文字列を結果として返す Activity を開始する処理を作成します。Intent を生成し、さきほど取得した ActivityResultLauncher の launch に Intent を渡して、Activity を開始します。

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        findViewById<Button>(R.id.inputButton)
            .setOnClickListener {
                val intent = SubActivity.createIntent(this)
                subActivityLauncher.launch(intent)
            }
    }

以上で、文字列を結果として返す Activity からその文字列を取得できるようになります。

Fragment で Activity Result API を使う

ライブラリのインポート

Fragment で Activity Result API を使う場合、アプリの build.gradle ファイルの dependenciesfragment-ktx を追加してください。

dependencies {
    implementation "androidx.fragment:fragment-ktx:1.4.1"
}

他の Activity の結果を取得する

ここから、Activity Result API で他の Activity の結果を取得する Fragment を作成します。

なお、文字列を結果として返す Activity については、Activity で Activity Result API を使う場合と同様なので、ここでは省略します。

以下が、実際のコードです。

class MainFragment : Fragment(R.layout.main_fragment) {

    private val subActivityLauncher = registerForActivityResult(
        ActivityResultContracts.StartActivityForResult()
    ) { result ->
        if (result.resultCode == RESULT_OK) {
            view?.let { view ->
                val text = result.data?.getStringExtra(SubActivity.EXTRA_RESULT) ?: ""
                val textView = view.findViewById<TextView>(R.id.resultTextView)
                textView.text = text
            }
        }
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        view.findViewById<Button>(R.id.inputButton)
            .setOnClickListener {
                val intent = SubActivity.createIntent(requireContext())
                subActivityLauncher.launch(intent)
            }
    }
}

Activity のときと同様に、registerForActivityResult を使って、他のアクティビティを開始するために使用する ActivityResultLauncher を取得します。

    private val subActivityLauncher = registerForActivityResult(
        ActivityResultContracts.StartActivityForResult()
    ) { result ->
        if (result.resultCode == RESULT_OK) {
            view?.let { view ->
                val text = result.data?.getStringExtra(SubActivity.EXTRA_RESULT) ?: ""
                val textView = view.findViewById<TextView>(R.id.resultTextView)
                textView.text = text
            }
        }
    }

そして、文字列を結果として返す Activity を開始する処理を作成します。こちらも、Activity のときと同様です。

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        view.findViewById<Button>(R.id.inputButton)
            .setOnClickListener {
                val intent = SubActivity.createIntent(requireContext())
                subActivityLauncher.launch(intent)
            }
    }

以上で、Fragment でも文字列を結果として返す Activity からその文字列を取得できるようになります。