论__AlertDialog自定义布局回调修改的正确方式

论__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线程”));

Github

GithubDemo代码

上一篇:linux系统误删文件怎么办!使用extundelete恢复数据


下一篇:Linux下使用curl