これは
遷移先のActivityから処理結果を得るには、これまでonActivityResult
をオーバーライドし、requestCodeで分岐するような実装が必要でした。
androidx.activity:1.2.0
、で代替手段となるコールバック方式のAPI registerForActivityResult
が提供されています。
これをRxJavaやKotlin Coroutinesと一緒に使うことで、処理結果であるActivityResult
を待ち合わせる実装をしてみます。
Normalな実装
registerForActivityResult
の基本的な使い方は上記の公式ガイドを見ていただくとして、後述する実装と統一感をもたせるためregisterForActivityResult
をラップした実装を載せておきます。
class NormalStartActivityForResultLauncher( activity: ComponentActivity, action: (ActivityResult) -> Unit, ) { private val startActivityForResult = activity.registerForActivityResult( StartActivityForResult() ) { activityResult -> action(activityResult) } fun launch(intent: Intent) { startActivityForResult.launch(intent) } }
これはこう使います。
private val normalLauncher = NormalStartActivityForResultLauncher(this) { activityResult -> // なにか処理 } val intent = Intent(this, TargetActivity::class.java) normalLauncher.launch(intent)
TargetActivity
の結果をコールバックで得ることができます。
RxJavaな実装とKotlin Coroutinesな実装
RxJava
Single
を使ってこのような実装をしてみました。RxJava3を利用しています。
class RxStartActivityForResult( activity: ComponentActivity ) { private var emitter: SingleEmitter<ActivityResult>? = null private val startActivityForResultLauncher = activity.registerForActivityResult( StartActivityForResult() ) { emitter?.onSuccess(it) } fun launch(intent: Intent): Single<ActivityResult> { startActivityForResultLauncher.launch(intent) return Single.create { emitter = it } } }
コールバックで取得したActivityResult
をemitter::onSuccessで渡しています。
これはこんな感じに使えます。
private val rxLauncher = RxStartActivityForResult(this) val intent = Intent(this, TargetActivity::class.java) rxLauncher.launch(intent) .subscribeOn(Schedulers.single()) .observeOn(AndroidSchedulers.mainThread()) .subscribe { activityResult -> // なにか処理 }
Kotlin Coroutines
同じような要領で実装します。CompletableDeferred
を使ってみました。
class DeferredStartActivityForResultLauncher( activity: ComponentActivity ) { private var deferred: CompletableDeferred<ActivityResult>? = null private val startActivityForResultLauncher = activity.registerForActivityResult( StartActivityForResult() ) { deferred?.complete(it) } fun launch(intent: Intent): CompletableDeferred<ActivityResult> { startActivityForResultLauncher.launch(intent) deferred = CompletableDeferred() return deferred!! } }
利用側はこんな感じです。
private val deferredLauncher = DeferredStartActivityForResultLauncher(this) lifecycleScope.launch { val intent = Intent(this, TargetActivity::class.java) val activityResult = deferredLauncher.launch(intent).await() // なにか処理 }
さいごに
コールバックではなくRxJavaやKotlin Coroutinesを使う必要があるユースケースはあまり多くないように思いますが、registerForActivityResult
の登場でこういう実装もしやすくなったと感じます。
挙げているコードはこちらに置いています。