前回、ActivityResultContractの使い方を書きましたが、いくつか実装時の注意があります。
TL;DL
prepareCall
は private変数の宣言と同時に呼ぶ- もしくは、
onCreate
でprepareCall
を呼ぶ prepareCall
を呼ぶ順番が分岐などで変わらないようにする
問題点
以下のようなコードを書いてると画面回転などでActivityがシステムによって再生成したときにクラッシュする可能性があります。
- 例えば、
prepareCall
をボタンイベントなどで呼び出した場合 prepareCall
が条件分岐等で順番が変わったりする場合
解説
まず、 prepareCall
が簡単に何をしてるかというと、 ActivityResultRegistry
というクラスに 呼び出すたびにインクリメントされるKey を使って ActivityResultContract
の情報を識別しています。
また、このKeyは onSavedInstanceState
で保存されておりActivity再生成時も保持し続けます。
このKeyを使って onActivityResult
からどの処理を呼び出すかが決まります。
Activity再生成時には onActivityResult
が処理される前にこれらの情報を再登録させておく必要があります。そのため prepareCall
は onCreate
もしくは 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 multipleActivityResultLauncher
instances. You must always callprepareCall()
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
をデバッグ実行で追っていくわかりやすいと思います。