ActivityResultContractsの仕組み、個人的にちょっとどうかな?と思っているところがあります。
それは、リクエスト内容と、結果の処理の結びつきが弱く、余計な自由度が残されてしまうところです。
例えばパーミッションのリクエストの場合、以下のように記述します。
private val launcher =
registerForActivityResult(RequestPermission()) {
// 結果の処理
}
...
// リクエスト
launcher.launch(Manifest.permission.CAMERA)
ここで、リクエストしているパーミッションと、その結果の処理は紐付いています。にもかかわらず、コールバックの登録時点でリクエストするパーミッションは決まっておらず、lauchをコールする時点で自由度が残されています。ここで間違って異なるパーミッションを指定してしまうと意図した動作となりません。
registerをコールした時点でこの対応関係が固定できないところがちょっとモヤモヤします。
もちろん、リクエスト内容が動的に変わりうるなど、自由度がないと困るケースもあるので、そちらに倒されているのだとは思いますが、もうちょっとうまいやり方はないものかと思ってしまいます。
解消する拡張関数
ActivityとFragmentそれぞれに拡張関数を作ってしまえば良いでしょう。
前述のパーミッションリクエストの例で言えば
private val launcher =
registerForActivityResultWrapper(RequestPermission(), Manifest.permission.CAMERA) {
// 結果の処理
}
...
// リクエスト
launcher.launch()
このように、リクエストとその結果の処理の対応関係を固定してしまうことができます。
余計な自由度がなくなりシンプルにすることができます。
実装は以下
fun <I, O> Fragment.registerForActivityResultWrapper(
contract: ActivityResultContract<I, O>,
input: I,
callback: ActivityResultCallback<O>
): ActivityResultLauncherWrapper<I> =
ActivityResultLauncherWrapper(registerForActivityResult(contract, callback), input)
fun <I, O> Fragment.registerForActivityResultWrapper(
contract: ActivityResultContract<I, O>,
registry: ActivityResultRegistry,
input: I,
callback: ActivityResultCallback<O>
): ActivityResultLauncherWrapper<I> =
ActivityResultLauncherWrapper(registerForActivityResult(contract, registry, callback), input)
fun <I, O> FragmentActivity.registerForActivityResultWrapper(
contract: ActivityResultContract<I, O>,
input: I,
callback: ActivityResultCallback<O>
): ActivityResultLauncherWrapper<I> =
ActivityResultLauncherWrapper(registerForActivityResult(contract, callback), input)
fun <I, O> FragmentActivity.registerForActivityResultWrapper(
contract: ActivityResultContract<I, O>,
registry: ActivityResultRegistry,
input: I,
callback: ActivityResultCallback<O>
): ActivityResultLauncherWrapper<I> =
ActivityResultLauncherWrapper(registerForActivityResult(contract, registry, callback), input)
class ActivityResultLauncherWrapper<I>(
private val launcher: ActivityResultLauncher<I>,
private val input: I
) {
fun launch() = launcher.launch(input)
fun launch(options: ActivityOptionsCompat) = launcher.launch(input, options)
fun unregister() = launcher.unregister()
fun getContract(): ActivityResultContract<I, *> = launcher.contract
}
拡張関数をつくってすっきり、と言いたいところですが、今度はWrapperはないだろうとモヤモヤし始めました。
良い名前があれば教えてください。