startActivityForResult , onActivityResult は廃止されます。これに関しては既に内部的には ActivityResultContract 等を使用するように置き換えられています。

用途
Intentを作成して起動( startActivityForResult ) -> 結果を受け取るもの( onActivityResult )は今後これを使います。
使い方
ActivityやFragmentでとあるファイルをダウンロードして書き込みを行いたいとしたら、以下のようにします。
(今はScoped Storageの話は忘れてください)
private val launcher = registerForActivityResult(ActivityResultContracts.RequestPermission()) { it : ActivityResultCallback -> if (it) { // TODO: ダウンロード -> 書き込み処理 } } fun download() { launcher.launch(Manifest.permission.READ_EXTERNAL_STORAGE) }
解説
ActivityResultContract , ActivityResultLauncher , ActivityResultCallback の3つが登場します。
registerForActivityResult で ActivityResultContract と ActivityResultCallback を指定します。
すると戻り値で ActivityResultLauncher が取得できます。
ActivityResultLauncher に対して launch を行うと ActivityResultContracts で指定された処理が行われ、 ActivityResultCallback に結果がやってきます。
実装を見る
ActivityResultLauncher はライブラリ側がよしなにやってくれるので今回は解説しません。
使用するだけなら ActivityResultContracts と ActivityResultCallback の実装だけわかっていれば大丈夫です。
ActivityResultCallback
ActivityResultContracts は良く使われるであろうものは既に定義されています。 ActivityResultContracts.RequestPermission() がそうです。
以下の3つ、最低2つを実装してあげるだけで大丈夫です。 parseResult を見ると requestCode という概念は存在しません。内部で使用されている ActivityResultRegistry がよしなにやってくれるので requestCode の管理から開放されます。
/** * Iで引数を指定する * Oで戻り値を指定する **/ public abstract class ActivityResultContract<I, O> { // Activity#setResult()で結果を返してくれるIntentを生成する public abstract @NonNull Intent createIntent( @NonNull Context context, @SuppressLint("UnknownNullness") I input ); // Intentを「O」にパースして返す @SuppressLint("UnknownNullness") public abstract O parseResult( int resultCode, @Nullable Intent intent ); // デフォルトでnullなので実装しなくても良い // ここで結果を返すとcreateIntentが呼ばれす、そのまま結果を返す。 public @Nullable SynchronousResult<O> getSynchronousResult( @NonNull Context context, @SuppressLint("UnknownNullness") I input ) { return null; } }
ActivityResultCallback
ActivityResultCallback の結果の「O」が渡されるだけです。
public interface ActivityResultCallback<O> { void onActivityResult(@SuppressLint("UnknownNullness") O result); }
おまけ
使用する側でlaunchするわけですが、使用する側が使用するPermissionを意識するのって微妙じゃないですかね。
private val launcher = registerForActivityResult(ActivityResultContracts.RequestPermission()) { it : ActivityResultCallback -> if (it) { // TODO: ダウンロード -> 書き込み処理 } } fun download() { launcher.launch(Manifest.permission.READ_EXTERNAL_STORAGE) }
というわけで、この様に書き換えてみました。普通に関数のように使用できます。
private val doDownload = object { private val launcher = registerForActivityResult(ActivityResultContracts.RequestPermission()) { } operator fun invoke() { launcher.launch(Manifest.permission.READ_EXTERNAL_STORAGE) } }
Scoped Storage 等で特定OSバージョンで権限要らないなとなった場合は以下のように書けます。
private val doDownload = object { private val launcher = registerForActivityResult(ActivityResultContracts.RequestPermission()) { if (it) { download() } else { // TODO: Error message } } operator fun invoke() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { download() } else { launcher.launch(Manifest.permission.READ_EXTERNAL_STORAGE) } } private fun download() { // TODO } }