欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android开发笔记之:Dialog的使用详解

程序员文章站 2023-11-20 17:40:10
dialog是任何系统都必须有的一个控件,作为辅助窗口,用于显示一些消息,或请求用户采取一引起操作等。在android中也不例外,基本使用可能参看文档。使用时的注意事项1....
dialog是任何系统都必须有的一个控件,作为辅助窗口,用于显示一些消息,或请求用户采取一引起操作等。
在android中也不例外,基本使用可能参看文档。
使用时的注意事项
1. back键能取消掉对话框(dismiss),但是却不会触发其onokey和oncancel回调接口,所以如果你的对话框会改某些状态,一定要注意还有第三种方式取消对话框。
2. 尽量少用模态对话框(model dialog),如果dialog.setcancellable(false),就变成了一个模态对话框,除了程序内部把其dismiss,否则按什么键都无法将其取消。这是极差的用户体验,对话框本身就是一种干扰,再无法取消会把用户搞疯的。所以除非特别有必要,也即当执行某个操作时不希望被打破,才可以使用模态对话框。
3. 尽量少用对话框,它对用户是一种干扰,除非需要用户做操作,或者做出选择。通常的一般性的通知用toast或者notification就足够了。
4. 不要使用对话框风格的activity,也即把activity变成一个对话框。因为这样是自已定义的布局,与系统dialog的风格可能会不一致。最严重的是当系统风格发生变化,dialog的子类会变化,但activity式的对话框就不会变化。可以在ics中找一找activity对话框,你会发现其ok是在左边,而ics中系统dialog的ok都是在右边的。
5. 尽量保证dialog对象活在activity的生命周期之内,也即至多是在oncreate()和ondestroy()之间。
6. 要想到和测试到activity在其dialog.dismiss()之前死掉的情况。因为activity必须依附于某个正在显示的activity实例,当显示和取消的时候其activity实例必须存在,否则就会有"illegalargumentexception: view not attached to window manager"。
复制代码 代码如下:

05-15 02:45:26.320: e/androidruntime(1161): java.lang.illegalargumentexception: view not attached to window manager
05-15 02:45:26.320: e/androidruntime(1161):     at android.view.windowmanagerimpl.findviewlocked(windowmanagerimpl.java:355)
05-15 02:45:26.320: e/androidruntime(1161):     at android.view.windowmanagerimpl.removeview(windowmanagerimpl.java:200)
05-15 02:45:26.320: e/androidruntime(1161):     at android.view.window$localwindowmanager.removeview(window.java:432)
05-15 02:45:26.320: e/androidruntime(1161):     at android.app.dialog.dismissdialog(dialog.java:278)
05-15 02:45:26.320: e/androidruntime(1161):     at android.app.dialog.access$000(dialog.java:71)
05-15 02:45:26.320: e/androidruntime(1161):     at android.app.dialog$1.run(dialog.java:111)
05-15 02:45:26.320: e/androidruntime(1161):     at android.app.dialog.dismiss(dialog.java:268)
05-15 02:45:26.320: e/androidruntime(1161):     at com.hilton.effectiveandroid.app.dialogdemo$1.handlemessage(dialogdemo.java:26)
05-15 02:45:26.320: e/androidruntime(1161):     at android.os.handler.dispatchmessage(handler.java:99)

7. dialog.show()必须在主线程里调用,但dialog.dismiss()却可以在任何线程中调用。
三种使用方式比较
1. 直接创建一个局部的dialog对象
优点是变量是局部的容易理解和维护。缺点是dialog对象难以控制,容易引发runtimeexception。
2. 把dialog对象变成activity的域
优点是dialog对象可以重复利用,且activity可以控制以保证dialog不会在activity生命周期外显示。是推荐的使用方式。
3. 用activity的方法oncreatedialog(), showdialog()和dismissdialog()
优点是frameworks会帮忙照看dialog,在大多数情况下这是推荐的做法。但是对于activity提前死掉的情况,此方法必有runtimeexception,且无法回避。
实例
复制代码 代码如下:

public class dialogdemo extends activity {
    private static final int dismiss_dialog = 1;

    private progressdialog mbetterdialog;
    private handler mmainhandler = new handler() {
 @override
 public void handlemessage(message msg) {
     switch (msg.what) {
     case dismiss_dialog:
  dialog dialog = (dialog) msg.obj;
  dialog.dismiss();
  break;
     default:
  break;
     }
 }
    };
    @override
    protected void oncreate(bundle savedinstancestate) {
 super.oncreate(savedinstancestate);
 setcontentview(r.layout.dialog_demo);

 final button sucking = (button) findviewbyid(r.id.sucking);
 sucking.setonclicklistener(new view.onclicklistener() {
     public void onclick(view v) {
  final activity activity = dialogdemo.this;
  final progressdialog dialog = new progressdialog(activity);
  dialog.settitle("worst dialogging");
  dialog.setmessage("this is the worst dialogging scheme, never use it. this dialog is easy to " +
   "run out of its attached activity, yielding windowmanager#badtokenexception if the activity is gone when dismissing");
  dialog.setindeterminate(true);
  dialog.setcancelable(true);
  // you must do the show in main thread anyway
  dialog.show();
  new thread(new runnable() {
      public void run() {
   systemclock.sleep(10000);
   /*
    * illegalargumentexception: view not attached to window manager
    * if the activity showing the dialog was killed before dismiss() out of rotation or locale changed,
    * the dialog will gone with activity, but when dismiss() yields "illegalargumentexception: view not attached to
    * window manager".
    * checking isshowing() won't help.
    * checking activity.isfinishing() won't help, either.
    * dismiss it in main thread also won't give any help.
    */
   // this won't work
//   if (dialog.isshowing()) {
//       dialog.dismiss();
//   }
//   if (!activity.isfinishing()) {
//       dialog.dismiss();
//   }
   message msg = message.obtain();
   msg.what = dismiss_dialog;
   msg.obj = dialog;
   mmainhandler.sendmessage(msg);
      }
  }).start();
     }
 });

 final button better = (button) findviewbyid(r.id.better);
 better.setonclicklistener(new view.onclicklistener() {
     public void onclick(view v) {
  mbetterdialog = new progressdialog(dialogdemo.this);
  mbetterdialog.settitle("better dialogging");
  mbetterdialog.setmessage("this dialogging can be used. the dialog object is a field of its activity, so activity can" +
    " control it to make sure dialog only lives within activity lifecircle");
  mbetterdialog.setindeterminate(true);
  mbetterdialog.setcancelable(true);
  // you must do the show in main thread anyway
  mbetterdialog.show();
  new thread(new runnable() {
      public void run() {
   systemclock.sleep(10000);
   /*
    * this is much better, mbetterdialog is a field of its activity, so activity can take care of it in order
    * to make sure dialog only live within activity's life circle, to avoid any unexpected exceptions.
    */
   // this really works
       if (mbetterdialog != null && mbetterdialog.isshowing()) {
           mbetterdialog.dismiss();
       }
      }
  }).start();
     }
 });

 final button optional = (button) findviewbyid(r.id.optional);
 optional.setonclicklistener(new view.onclicklistener() {
     @suppresswarnings("deprecation")
     public void onclick(view v) {
  showdialog(0);
  new thread(new runnable() {
      public void run() {
   systemclock.sleep(10000);
   /*
    * this way works best for most of time, except if activity died before dismissing, exception must be
    * thrown: "illegalargumentexception: view not attached to window manager".
    * although activity takes care of its belonging dialog, there is no way to operate it manually any more.
    * first you do not have reference to dialog object and second, any manual operation only interferences
    * and breaks state maintained by frameworks.
    */
   dismissdialog(0);
      }
  }).start();
     }
 });
    }
    @override
    protected dialog oncreatedialog(int id) {
 progressdialog d = new progressdialog(this);
 d.settitle("optional dialogging");
 d.setmessage("this dialogging scheme works best for most times, the dialogs are all taken care of by activitys and frameworks" +
   ". except for activity being killed during dialog showing");
 d.setindeterminate(true);
 d.setcancelable(true);
 return d;
    }
    @override
    protected void ondestroy() {
 super.ondestroy();
 // activity is dying, all its belonging dialogs should be dismissed, of course.
 if (mbetterdialog != null && mbetterdialog.isshowing()) {
     mbetterdialog.dismiss();
     mbetterdialog = null;
 }
 // for dialogs showed via showdialog(int), no way to stop it in ondestroy()
// dismissdialog(0); // cause "illegalargumentexception: no dialog with id 0 was ever shown via activity#showdialog"
       // this is because activity has to manage its dialog during onpause() and onresume() to restore
                   // dialogs' state. so if you manually dismiss it in ondestroy(), it will cause je.

// removedialog(0);// cause "illegalargumentexception: no dialog with id 0 was ever shown via activity#showdialog", when
   // dismissing in thread.
               // this is because activity has to manage its dialog during onpause() and onresume() to restore
                     // dialogs' state. so if you manually dismiss it in ondestroy(), it will cause je.
    }
}