先日、α版をリリースしましたが、いくつもバグを出してしまいました(申し訳ありません)。いくつかはまった点を書いておきます。多少ともどなたかの参考になれば幸いです。
Activityのライフサイクルを確認するときは開発者オプションを使う
最もバグが出てしまったのは、Activityの状態管理の部分です。このゲームでも、Androidの仕様通り、ActivityのonCreateやonPause等で、BundleにActivityの状態を保存しています(所持金や所持品、パーティ情報など)。この処理は最初から組み込んであったのですが、テスト環境(エミュレータおよび実機)では、ほとんど動作していなかったようです。テスト中にはそのアプリしか動かさないので、Activityがずっと保持されていたわけです。
開発者オプションの「アクティビティを保持しない」にチェックを入れると、Activityから離れたときに、すぐにGCされるようになるようです。リリース前に必ずこの状態でテストしたほうがよいでしょう。
ParcelクラスのreadParcelableに指定するクラスローダ
Parcelから、Parcelableのオブジェクトを取り出すときに使うのがreadParcelableメソッドですが、この引数に指定するクラスローダは、アプリのクラスローダにする必要があるようです(Androidのクラスローダにはシステムクラスローダとアプリのクラスローダがある、参考)。readParcelable(null)とすると、システムクラスローダが使用され、ClassNotFoundExceptionになります。以下のようにするといいようです。
dungeonContext = source.readParcelable(this.getClass().getClassLoader());
Activity間で共有するインスタンスとライフサイクルに注意する
Activityの遷移時に大きめのデータを渡すとき、以下のページにあるようにpublic static fieldでデータを共有しています。- How do I pass data between Activities/Services within a single application?
http://developer.android.com/guide/faq/framework.html#3
このとき、前のActivityは遷移後もなくなったわけではなく、次のActivityが生成された後で、onPauseやonDestroyが呼ばれることがあります。そこで、共有したオブジェクトを操作してしまうと(たとえばBundleに保存するなど)、わかりにくいバグが起きる可能性があります。
渡した後は触らないようにするか、素直にIntentを使うのがよさそうです。
ダイアログ表示ボタンを連打するとDialogFragmentが二重に表示される
ボタン連打でダイアログが二重に表示される問題は以前からありました。前作ではDialogFragmentは使っていませんでしたので、「表示する処理(ボタンの処理)で表示中かどうか判定する」という泥臭い処理を行っていました。今回はダイアログの数が増えていますので、すべてにその処理をいれるのは面倒です。また、DiagloFragmentを使うようにしたので、共通化ができそうです。
そこで、以下のブログの記事を参考にさせていただきました。有用な記事をありがとうございます。
- EGG 開発ブログ: ダイアログが重ならないように制御する
http://eggdev.mobaegg.com/2012/08/blog-post_4.html
ただ、これでも「二つのボタンを同時押しする」と二重に表示されてしまいます。実機だと、二本指でタップすることで、容易に再現できます。
ですので、アプリのダイアログ基底クラスに、以下のように表示中フラグを導入しました。とりあえず問題なく動作しているようです。
private static boolean dialogShowing = false; // 表示中フラグ private static Object lock = new Object(); // ロック用(いらないかも) public void show(FragmentManager manager) { synchronized (lock) { if (dialogShowing) { return; } dialogShowing = true; } dismissPreviousDialog(manager, ALERT_DIALOG_FIXED_TAG); super.show(manager, ALERT_DIALOG_FIXED_TAG); } @Override public void onResume() { super.onResume(); synchronized (lock) { dialogShowing = false; } } private void dismissPreviousDialog(FragmentManager manager, String tag) { AlertDialogFragment prev = (AlertDialogFragment) manager.findFragmentByTag(tag); if (prev != null) { // フラグメントが表示されていなければ処理なし Dialog dialog = prev.getDialog(); if (dialog != null) { // ダイアログがなければ処理なし if (dialog.isShowing()) { // ダイアログが表示されていなければ処理なし prev.dismiss(); // ダイアログ消去 } } } }
0 件のコメント:
コメントを投稿