【Kotlin/Android Studio】registerForActivityResultの使い方!launcherとは?

【Kotlin/Android Studio】registerForActivityResultの使い方!launcherとは?

この記事からわかること

  • Android Studio/KotlinregisterForActivityResult使い方
  • 別のActivity起動させるには?
  • Activityの結果取得する方法
  • StartActivityForResultの挙動
  • ActivityResultContract設定値
  • RequestPermission/RequestMultiplePermissionsを使用したパーミッションダイアログの結果取得

index

[open]

\ アプリをリリースしました /

みんなの誕生日

友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-

posted withアプリーチ

環境

Activity Result API

公式リファレンス:アクティビティの結果を取得する

Androidアプリではある画面から別の画面(Activity)を起動させる仕組みとして「Activity Result API」が用意されています。昔はstartActivityForResultonActivityResultを使用してActivityの起動と結果の受け取りを行なっていましたが、これらは非推奨になり新しく「Activity Result API」が定義されました。

// 呼び出し側
val intent = Intent(this, NextActivity::class.java)
startActivityForResult(intent, REQUEST_CODE)

// 結果を受け取る
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    if (requestCode == REQUEST_CODE && resultCode == Activity.RESULT_OK) {
        val result = data?.getStringExtra("result")
    }
}

Activity Result API」の1つがregisterForActivityResultです。

registerForActivityResult


abstract @NonNull ActivityResultLauncher<I> <I, O> registerForActivityResult(
    @NonNull ActivityResultContract<I, O> contract,
    @NonNull ActivityResultCallback<O> callback
)

registerForActivityResult別のアクティビティを起動し結果を取得することができるメソッドです。引数としてActivityResultContract型を受け取りActivityResultLauncher型を返します。


private val launcher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
  // 結果に対する処理
}

※ランチャーとは機能を保持し、あとは簡単な操作のみで起動させるだけの機能のことです。

ActivityResultContract型

公式リファレンス:ActivityResultContract

ActivityResultContractには使用頻度の高いContract(契約)があらかじめ複数定義されています。

ActivityResultContract 概要
StartActivityForResult 任意のActivityを起動して結果を取得
RequestPermission 単体のパーミッション許可ダイアログを表示して結果を取得
RequestMultiplePermissions 複数個のパーミッション許可ダイアログを表示して結果を取得
GetContent / GetMultipleContents ギャラリーなどからURI経由で取得
TakePicture カメラで写真を撮ってURI経由で取得

ActivityResultCallback

registerForActivityResultの2つ目の引数ActivityResultCallback(コールバック)で実際の結果を受け取ることが可能になっています。

Jetpack Composeでの実装:rememberLauncherForActivityResult

Jetpack Composeで実装している場合はrememberLauncherForActivityResultを使用します。基本的な使い方はあまり変わらず引数にActivityResultContractsを指定しManagedActivityResultLauncher型で結果の処理を含んだランチャーを取得することができます。

val launcher = rememberLauncherForActivityResult(
    contract = ActivityResultContracts.StartActivityForResult()
) { result ->
    if (result.resultCode == Activity.RESULT_OK) {
        // 結果の処理
    }
}

別のActivityからデータを受け取る

今回はSecondActivityから入力されたデータをMainActivityで表示させてみます。1アプリ1Activityが基本なので設計上破綻しているかもしれませんが動作確認だけしてみます。

【Kotlin/Android Studio】registerForActivityResultの使い方!launcherとは?

MainActivity側でregisterForActivityResultメソッドを呼び出します。1つ目の引数にはActivityResultContracts.StartActivityForResultを渡します。Activityから返ってくる値はコールバックで受け取れるので変数resultに格納し、resultCodeプロパティから識別コードを、dataプロパティからIntentを参照することができます。


class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val button: Button = findViewById(R.id.done_button)

        button.setOnClickListener {
            // SecondActivityに送信する用のデータを準備する
            val intent = Intent(applicationContext, SecondActivity::class.java)
            // SecondActivityを起動
            launcher.launch(intent)
        }
    }

    // SecondActivityを起動する機能と結果を処理する機能をもったランチャー(ActivityResultLauncher型)
    private val launcher =
    registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
        // Resultコードをチェック
        if (result.resultCode == Activity.RESULT_OK) {
            // インテントを取得
            val intent = result.data
            // 中身を取り出す
            val name = intent?.getStringExtra("name")
            // 表示
            Toast.makeText(this, name, Toast.LENGTH_SHORT)
                .show()
        }
    }
}

Intentの使い方は以下の記事を参考にしてください。

SecondActivity側はsetResultメソッドを使用して結果として返すデータを設定します。1つ目の引数にはActivity.RESULT_OKActivity.RESULT_CANCELEDなどの識別コードを渡し、2つ目にはIntentを渡します。


public final void setResult(int resultCode, Intent data) {
    throw new RuntimeException("Stub!");
}

最後にActivityを終了するfinishメソッドを呼び出して完了です。


class SecondActivity : AppCompatActivity() {

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

        val name: EditText = findViewById(R.id.name_edit)
        val backBtn:Button = findViewById(R.id.back_button)
        backBtn.setOnClickListener {
            // インテントに値をセット
            intent.putExtra("name", name.text.toString())
            // 結果として返すデータをセット
            setResult(Activity.RESULT_OK, intent)
            // アクティビティを終了
            finish()
        }
    }
}

これで以下のような機能を実装することができました。

【Kotlin/Android Studio】registerForActivityResultの使い方!launcherとは?

RequestPermission:パーミッションダイアログを表示する

おすすめ記事:【Kotlin/Android Studio】パーミッション(権限)許可のリクエスト方法!requestPermissions

registerForActivityResultの引数にRequestPermissionを渡すことで簡単にパーミッション許可申請ダイアログを表示することができます。ダイアログを出す際は忘れずにマニフェストファイルの追加をしといてください。

<uses-permission android:name="android.permission.CAMERA" />

実装は以下のとおりです。

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

        // 許可ダイアログを表示
        launcher.launch(Manifest.permission.CAMERA)
    }

    private val launcher =
        registerForActivityResult(ActivityResultContracts.RequestPermission()) { result ->
            // ダイアログの結果で処理を分岐
            if (result) {
                Toast.makeText(this, "許可されました", Toast.LENGTH_SHORT)
                    .show()
            } else {
                Toast.makeText(this, "否認されました", Toast.LENGTH_SHORT)
                    .show()
            }
        }
}
【Kotlin/Android Studio】パーミッション(権限)許可のリクエスト方法!requestPermissions

RequestMultiplePermissions:複数のパーミッションダイアログを表示する

複数のパーミッションダイアログを表示するにはRequestMultiplePermissionsを指定します。

class MainActivity : AppCompatActivity() {

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

        launcher.launch(
            arrayOf(
                Manifest.permission.CAMERA,
                Manifest.permission.ACCESS_COARSE_LOCATION
            )
        )
    }

    private val launcher =
        registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) {
            it
            val camera = it[Manifest.permission.CAMERA] ?: false
            val location = it[Manifest.permission.ACCESS_COARSE_LOCATION] ?: false

            if (camera && location) {
                Toast.makeText(this, "許可されました", Toast.LENGTH_SHORT)
                    .show()
            } else {
                Toast.makeText(this, "否認されました", Toast.LENGTH_SHORT)
                    .show()
            }
        }
}

GetContent:ギャラリーなどからファイルを取得

ギャラリーなどから画像を取得するにはGetContentを使用します。選択した画像を直接取得できるわけではなく取得できるのはURI(Uniform Resource Identifier)になります。URI(=参照)を取得するのでcontentResolverを介して実際のデータを取得する処理を実装する必要があります。

@Composable
fun ImagePickerSample(viewModel: MyViewModel = viewModel()) {
    val context = LocalContext.current

    val launcher = rememberLauncherForActivityResult(
        contract = ActivityResultContracts.GetContent()
    ) { uri: Uri? ->
        uri?.let {
            val source = ImageDecoder.createSource(context.contentResolver, it)
            val bitmap = ImageDecoder.decodeBitmap(source)

            // ViewModelなどに渡す
            viewModel.onImageSelected(bitmap)
        }
    }

    // ボタンでギャラリーを開く
    Button(onClick = { launcher.launch("image/*") }) {
        Text("画像を選択")
    }
}

また選択できるファイル形式はMIMEタイプで指定することが可能です。

GetMultipleContents:ギャラリーなどからファイルを複数取得

複数取得したい場合はGetMultipleContentsを使用することができます。

val multiLauncher = rememberLauncherForActivityResult(
    contract = ActivityResultContracts.GetMultipleContents()
) { uris: List<Uri> ->
    uris.forEach { uri ->
        // URIごとに処理
    }
}

multiLauncher.launch("image/*")

エミュレーターのギャラリーに画像を追加する

エミュレーターでギャラリーから画像を選択する動作確認を行いたい場合はエミューレータのギャラリーに画像を入れ込む必要があります。他に方法があるかもしれないですが以下の方法でギャラリーに画像を追加することができました。

  1. エミュレーター起動
  2. エミュレーターに入れ込みたい画像をドラッグ&ドロップ
  3. エミュレーター内の「Files」アプリを起動(ダウンロードに先ほどの画像があるはず)
  4. 画像を選択し左下の「Share」をクリック
  5. これでギャラリーに画像が追加されました

まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。

ご覧いただきありがとうございました。

Search Box

Sponsor

ProFile

ame

趣味:読書,プログラミング学習,サイト制作,ブログ

IT嫌いを克服するためにITパスを取得しようと勉強してからサイト制作が趣味に変わりました笑今はCMSを使わずこのサイトを完全自作でサイト運営中〜

New Article

index