ActivityResultContractの注意

Kenji Abe
4 min readMar 23, 2020

--

前回、ActivityResultContractの使い方を書きましたが、いくつか実装時の注意があります。

TL;DL

  • prepareCall は private変数の宣言と同時に呼ぶ
  • もしくは、 onCreateprepareCall を呼ぶ
  • prepareCall を呼ぶ順番が分岐などで変わらないようにする

問題点

以下のようなコードを書いてると画面回転などでActivityがシステムによって再生成したときにクラッシュする可能性があります。

  • 例えば、 prepareCall をボタンイベントなどで呼び出した場合
  • prepareCall が条件分岐等で順番が変わったりする場合

解説

まず、 prepareCall が簡単に何をしてるかというと、 ActivityResultRegistry というクラスに 呼び出すたびにインクリメントされるKey を使って ActivityResultContract の情報を識別しています。

また、このKeyは onSavedInstanceState で保存されておりActivity再生成時も保持し続けます。

このKeyを使って onActivityResult からどの処理を呼び出すかが決まります。

Activity再生成時には onActivityResult が処理される前にこれらの情報を再登録させておく必要があります。そのため prepareCallonCreate もしくは private 変数宣言と同時に実行するなど、する必要があります。

また、Keyは単純にインクリメントされてるので prepareCall の順番も大事になります。これが条件分岐などで変わってしまうと、意図しないCallbackが呼び出されることになります。

ドキュメント

ドキュメントにも一応記載されるてるので、目を通しておくことをオススメします。

For this reason, the Activity Result APIs decouple the result callback from the place in your code where you launch the other activity. As the result callback needs to be available when your process and activity are recreated, the callback must be unconditionally registered every time your activity is created, even if the logic of launching the other activity only happens based on user input or other business logic.

If you have multiple activity result calls that either use different contracts or want separate callbacks, you can call prepareCall() multiple times to prepare multiple ActivityResultLauncher instances. You must always call prepareCall() in the same order for each creation of your fragment or activity to ensure that the inflight results are delivered to the correct callback.

コード

Android Studioから prepareCall をデバッグ実行で追っていくわかりやすいと思います。

https://cs.android.com/androidx/platform/frameworks/support/+/androidx-master-dev:activity/activity/src/main/java/androidx/activity/result/ActivityResultRegistry.java

--

--

Kenji Abe
Kenji Abe

Written by Kenji Abe

Programmer / Gamer / Google Developers Expert for Android, Kotlin / @STAR_ZERO

No responses yet