アクティビティから他のアクティビティを呼び出して、その結果を貰い何かを実行する場合がある。定石としてはonActivityResult
メソッドをオーバーライドして、その中で処理を実行するというものだが、この方法だと稀にわけの分からん例外が発生する。
📄BaseActivity.java
java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=1, result=-1, data=null} to activity {your_class}: java.lang.NullPointerException
この例外を発生させずに安全にコードを実行するサンプルを書いてみてる。
例外の原因
いろいろ調べてみた結果、次のような記事を発見した。
“Failure Delivering Result ” – onActivityForResult
この回答によると、
At the time that
onActivityResult()
is called, the activity/fragment’s state may not yet have been restored, and therefore any transactions that happen during this time will be lost as a result.
らしい。要するにonActivityResultが呼ばれたときにアクティビティ/フラグメントが完全にリストアされているかどうか保証されていないということ。
解決策としては復帰後に呼ばれるonPostResume
メソッドでやりたい処理を実行すればよいとのこと。これは順序的にはonActivityResult
=> onPostResume
=> onResume
にとなっており、onPostResume
メソッドは、アクティビティ/フラグメントがリストア済で呼び出されるようだ。
解決コード
というわけでStackoverflowの回答を発展させて、次のようなコードを書いた。
public abstract class BaseActivity extends AppCompatActivity { private class ActivityResult { private final int requestCode; private final int resultCode; private final Intent data; private ActivityResult(int requestCode, int resultCode, Intent data) { this.requestCode = requestCode; this.resultCode = resultCode; this.data = data; } } private ActivityResult activityResult; @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); activityResult = new ActivityResult(requestCode, resultCode, data); } @Override protected void onPostResume() { super.onPostResume(); if (activityResult != null) { onPostResumeWithActivityResult(activityResult.requestCode, activityResult.resultCode, activityResult.data); activityResult = null; } } protected void onPostResumeWithActivityResult(int requestCode, int resultCode, Intent data) { // override if necessary } }
大して難しいことはしていなくて、単にonActivityResult
メソッドで結果を保持しておいて、onPostResume
メソッドが呼び出されたときにonPostResumeWithActivityResult
メソッドを呼び出してあげる。
各アクティビティクラスは次のような感じになる。
📄MainActivity.java
public class MainActivity extends BaseActivity { ... @Override protected void onPostResumeWithActivityResult(int requestCode, int resultCode, Intent data) { super.onPostResumeWithActivityResult(requestCode, resultCode, data); // ここで煮るなり焼くなりする } ... }
各アクティビティのonPostResumeWithActivityResult
メソッドには、従来onAcitivityResult
メソッドに書いていた処理を書くことになるわけだ。
とりあえずこれで上手くいっている。なんか問題あったら教えてください。
関連する記事
- 【Android】10回に1回インタースティシャル広告を表示する
- Volleyでmultipartリクエストを送信する
- 【Android】フリックイベントを実装する
- 「で、結局オブジェクト指向って何が良いわけ?」という手続き型脳の貴男へ
- 【Android】リストビューの自動スクロール機能を実装する