误区一:(线程阻塞)
private void button1_click() throws InterruptedException {
AlertDialog dialog = new AlertDialog.Builder(this)
.setMessage("加载中...")
.show();
Thread.sleep(5000);
button1.setText("加载完毕");
dialog.dismiss();
}
以上代码,很多人描述看到的效果是:点击按钮后,弹出一个对话框,显示“加载中...”,5秒后按钮显示文字变成了“加载完毕”,对话框消失。
但是以上描述是错误的,你根本看不到对话框,你会发现事实上是这样的:点击按钮后,按钮没有抬起来,5秒后,按钮抬起来了,同时按钮文字变成了“加载完毕”。
我们发现原来整个过程中,AlertDialog毫无存在感,根本也看不到它出现,原因是因为,这里发生了UI线程阻塞。当要show出dialog的时候,下一句是Thread.sleep(5000),这句话的意思是,当前的线程睡眠5秒,也就是UI线程,因为这句代码没有写在子线程中,如果它写在了子线程中,那么睡眠的就是子线程了,而非主线程。当睡眠完后,马上修改按钮的文字,再让dialog消失,dialog的整个显示到消失,排除掉睡眠时间,肉眼根本无法捕捉到。
如果我们真的要达到很多人描述的那种效果,我们需要这样修改(且不说代码嵌套层次和优化):
private void button1_click() throws InterruptedException {
AlertDialog dialog = new AlertDialog.Builder(this)
.setMessage("加载中...")
.show();
new Thread(new Runnable() {
@Override
public void run() {
Thread.sleep(5000);
runOnUiThread(new Runnable() {
@Override
public void run() {
button1.setText("加载完毕");
dialog.dismiss();
}
});
}
}).start();
}
误区二:(cpu对线程的调度)
private void button1_click(View view) {
final AlertDialog dialog = new AlertDialog.Builder(this)
.setMessage("加载中...")
.show();
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(5000);
runOnUiThread(new Runnable() {
@Override
public void run() {
button1.setText("加载完毕1");
}
});
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
button1.postDelayed(new Runnable() {
@Override
public void run() {
button1.setText("加载完毕2");
dialog.dismiss();
}
},3000);
}
以上代码,很多人描述看到的效果是:点击按钮后,弹出一个对话框,显示“加载中…”,5秒后,按钮文字变成了“加载完毕1”,又停了3秒后,按钮问题变成了“加载完毕2”,对话框消失。
同样,以上描述也是错误的。我们可以理解线程的开启,就是一个任务块的开启,打开一个任务的开启,并不需要花费cpu什么时间,同样的,postDelayed也只是通知cpu,3秒后开启一个任务,也是不需要花多少时间的,至于具体去处理这些任务的时候,那又是另一个层面的事情,不会影响当前的代码执行顺序,也就是说,整个代码块,我们可以理解为在UI线程中,只给cpu下达了三个命令:弹出一个对话框,开一个子线程执行一个任务,3秒后执行一个任务。
所以,我们看到的效果应该是:点击按钮后,弹出一个对话框,显示“加载中…”,3秒后,按钮问题变成了“加载完毕2”,对话框消失,又过了2秒后,按钮文字变成了“加载完毕1”。