论__AlertDialog自定义布局回调修改的正确方式
本文由 Luzhuo 编写,请尊重个人劳动成果,转发请保留该信息.
原文: http://blog.csdn.net/Rozol/article/details/50441057
微博: http://weibo.com/u/2524456400
这几天写了个应用,自定义了
AlertDialog
布局,加入了TextView
和进度条展示,但是不管怎么调,Dialog
就是不显示出来,即时显示出来也不更新,只在程序执行完了才更新.
于是没辙了,换成Android自带的ProgressDialog
试试,结果还是老样子.(也是要么不显示,即时显示了也不更新,只在程序执行完了才更新.)
于是亲自动手写个Demo看看到底是什么问题.(反复折腾,终于折腾出结果来了,先下结论吧.)
这篇文章没有插图,下面有Github的链接,下载里面的apk就能很清楚的知道这篇文章在讲什么啦!!!
结论
- 一定要在辅助线程里执行的回调才能修改Dialog的界面; (第1,2的案例)
- 在ui线程里执行的回调不能修改Dialog的界面.(准确的说:能修改,但是不是你想要的效果) (第3,4的案例)
详细分析
先看
MainActivity
里的代码:public class MainActivity extends Activity implements OnClickListener { // ... 省略 private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case Start: dialog.show();// 显示 Log.i(TAG, "start"); break; case Back: textview.setText((String)msg.obj); Log.i(TAG, (String)msg.obj); break; case End: dialog.dismiss(); Log.i(TAG, "end"); break; } } }; // ... 省略 private void initData() { dialog_view = View.inflate(this, R.layout.dialog, null); textview = (TextView) dialog_view.findViewById(R.id.textview); // AlertDialog AlertDialog.Builder builder = new Builder(this); builder.setCancelable(false); dialog = builder.create(); dialog.setView(dialog_view, 0, 0, 0, 0); } private void threadStart() { DialogThread dialogThread = new DialogThread(); dialogThread.setOnBackListener(new OnBack() { @Override public void onStart() { Message msg = Message.obtain(); msg.what = Start; handler.sendEmptyMessage(Start); } @Override public void onBack(String backName) { Message msg = Message.obtain(); msg.what = Back; msg.obj = backName; handler.sendMessage(msg); } @Override public void onEnd() { Message msg = Message.obtain(); msg.what = End; handler.sendEmptyMessage(End); } }); dialogThread.start(); }
从上诉代码可以看出,我是让 子线程/异步任务/ui线程 里执行的任务通过回调方式.
然后在回调里发送Message
的方式更新ui.
由于 子线程/异步任务 都不能修改ui,所以使用发送Message
的方法,但是ui线程是可以直接修改Dialog
里的布局的,所以我会增加一个通过回调直接修改Dialog
的案例.
1.子线程里回调,修改dialog界面
第一种,通过开启子线程方式,然后回调修改dialog的界面.
由于子线程不能修改ui界面,所以使用handler方式.
public class DialogThread {
// ... 省略
public void start(){
new Thread(){
public void run() {
if(onBack != null) onBack.onStart();
while(x<10){
if(onBack != null) onBack.onBack(String.valueOf(x));
SystemClock.sleep(1000);
x++;
}
if(onBack != null) onBack.onEnd();
};
}.start();
}
// ... 省略
}
子线程通过执行回调,回调里发送
Message
修改Dialog的界面.
执行的结果是可行的,完全可以修改Dialog
的显示.效果非常好.
2.异步任务里回调,修改dialog界面
第二种,通过异步任务方式,然后回调修改dialog的界面.
由于辅助线程不能修改ui界面,所以使用handler方式.
public class DialogAsync extends AsyncTask<Context, Void, Void> {
// ... 省略
@Override
protected Void doInBackground(Context... params) {
if(onBack != null) onBack.onStart();
while(x<10){
if(onBack != null) onBack.onBack(String.valueOf(x));
SystemClock.sleep(1000);
x++;
}
if(onBack != null) onBack.onEnd();
return null;
}
// ... 省略
}
异步任务通过执行回调,回调里发送
Message
修改Dialog的界面.
执行的结果是可行的,完全可以修改Dialog
的显示.效果非常好.
3.UI线程里回调,修改dialog界面
第三种,通过ui线程方式,然后回调修改dialog的界面.
由于为了与上面的例子做个参照物,所以还是使用handler方式.
public class DialogThread {
// ... 省略
public void start(){
new Thread(){
public void run() {
if(onBack != null) onBack.onStart();
while(x<10){
if(onBack != null) onBack.onBack(String.valueOf(x));
SystemClock.sleep(1000);
x++;
}
if(onBack != null) onBack.onEnd();
};
}.start();
}
// ... 省略
}
ui线程通过执行回调,回调里发送
Message
修改Dialog的界面.
执行的结果是糟糕的,Log在程序执行完后才打印,而且是一起快速打印,而且根本没看到Dialog
的显示.
4.UI线程里回调,修改dialog界面
第四种,通过ui线程方式,然后回调修改dialog的界面.
由于为了与第三个例子做个参照物,所以直接回调然后修改Dialog的方式.
由于还是执行第三个例子的DialogThread
类的方法,代码这里不再粘贴.
这里粘贴MainActivity
里的部分主要代码.
public class MainActivity extends Activity implements OnClickListener {
// ... 省略
private void mainStart1() {
DialogMain dialogMain = new DialogMain();
dialogMain.setOnBackListener(new OnBack() {
@Override
public void onStart() {
dialog.show();// 显示
Log.i(TAG, "start");
}
@Override
public void onBack(String backName) {
textview.setText(backName);
Log.i(TAG, backName);
}
@Override
public void onEnd() {
dialog.dismiss();
Log.i(TAG, "end");
}
});
dialogMain.start();
}
}
ui线程通过执行回调,回调里直接修改Dialog的界面.
执行的结果是糟糕的,Log能完美的打印,但是根本没看到Dialog
的显示.
附
- Q:如何知道当前线程是否是ui线程?
- A:Log.i(“UIThread”, “当前线程”.concat(Thread.currentThread().getId() == 1 ? “是” : “不是”).concat(“UI线程”));