numalog

ぬまおうの活動日誌

Androidアプリ開発tips#2 ダイアログの表示について

with 2 comments

  • Dialog.show()は避けるべき

入門書なんかだと、ダイアログ表示するために、以下のようなコードを使うことが多いです。

    AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
    Dialog dialog = alertDialogBuilder.create();
    dialog.show();

結論から言うと、これは絶対に避けるべきです。
このソースコードにした場合、ユーザーからの閉じる操作、またはdialog.dismiss()によって適切にダイアログを閉じないと、リーク例外が出るからです。
つまり、これら2つ以外の、予期せぬ事態によってダイアログが閉じられたときエラーとなってしまいます。

そんなのってあるの?と思われるでしょうが、一つ例を挙げると画面回転があります。
Androidでは画面回転させると、いったんActivity破棄→再起動というプロセスが行われるのですが、このActivity破棄の際には画面に出ているダイアログは強制破棄されます。
つまり、ダイアログ回転に対応させるようなソースコードを一切書いていない場合、上2つの終了ケースに当てはまらないので例外となってしまうということです。
具体的に言うと、

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        if (dialog != null && dialog.isShowing()) {
            dialog.dismiss();
        }
    }

なんてものを書かなきゃいけないわけです。 1つならばいいのですが、複数ダイアログを使うアプリではその分書く必要があるし、   ダイアログの後処理忘れしてActivityが落ちるなんてことは、これ以外にも多々ありえるので、非常にカオスになりやすいです。
(プログラムのミスを除いても、メモリ不足でシステムが勝手にバックグラウンドActivityを落としたり等)
長く開発をしていると、「~ has leaked window」 というWindowLeakedエラーを一度は見たことがあるかと思いますが、大体は自前でViewやDialogの管理をしていたときに、適切な後処理が出来ていなくて発生するものです。

ではダイアログを使いたい場合どうするかというと、

  1. Activity#onCreateDialog, Activity#showDialog(int id)による管理をする
  2. Fragmentを使う

の2つのダイアログ表示方法があります。
2に関しては、2.x系ではデフォルトでは使用不可で、サポートライブラリを入れる必要があるので、とりあえずここでは1を紹介します。

厳密にはちょっと違いますが、イメージとしては、

  • Activityで、onCreateDialogをoverrideし、あらかじめ使う可能性のあるダイアログを、IDを割り振って登録しておく

  • Activity#showDialog(int id)で、登録してあったそのIDのダイアログをshowする

という流れになります。

具体的なコードは、Activity内で、
登録側

    @Override
    protected Dialog onCreateDialog(int id) {
        switch (id) {
        case 0: // ダイアログidを割り振っている
            AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
      Dialog dialog = alertDialogBuilder.create();
      return dialog; // 表示したいdialogをreturnする 
        default:
            return null;
        }
    }

使用側 onCreateや、他のメソッド内で

    this.showDialog(0);
    //onCreateDialog内で、0番IDを割り振ったDialogを表示<br />
  //具体的にはonCreateDialog(0)を呼んだときの戻り値となるDialogを表示している
    //一度showしたdialogは、dismissしてもインスタンスの使いまわしが行われる。
    this.dismissDialog(0);//基本はこっち。showDialogを再度すると、前のダイアログが使いまわされる
    this.removeDialog(0);//手動でダイアログの消去と、ダイアログ使い回しを破棄をしたい場合。
となります。

この方法で表示した場合、上記の回転処理や、予期せぬ終了を、Activity側がある程度自動で管理してくれるので、エラーが出る確率がぐっと減ります
慣れていないと回りくどく感じるかもしれませんが、Dialog.show()をするよりはるかにお勧めな方法です。
dialogに引数や値を渡したい場合は、代わりにonCreateDialog(int id, Bundle data)をoverrideし、showDialog(id, data)などと、bundleとして値を渡すことになります。
ただし、これは要求APIがAPI level 13で、IDのみ(API level 8)と比べて高くなってしまうので注意です。


Written by numa

6月 14th, 2013 at 2:48 am

Posted in プログラミング

Tagged with ,

2 Responses to 'Androidアプリ開発tips#2 ダイアログの表示について'

Subscribe to comments with RSS or TrackBack to 'Androidアプリ開発tips#2 ダイアログの表示について'.

  1. I read a lot of interesting posts here. Probably you spend
    a lot of time writing, i know how to save you a lot of time, there is an online tool
    that creates high quality, SEO friendly articles in minutes, just type in google
    - laranitas free content source

    Marilou

    19 9月 14 at 11:20 PM

  2. Nice post. I was checking constantly this blog and I am impressed! Extremely useful information specially the last part cdkeefedgeae

    Johnd721

    21 8月 16 at 8:59 PM

Leave a Reply