Android真的不能在子线程操作UI吗
很多很多很多很多。。。文章,书籍就会说一句,3.0之后将耗时操作必须放到子线程完成,主线程主要用来操作或者更新UI,但是我们深入分析其实一种极端情况是可以访问的。
看如下代码:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
foot = (TextView) findViewById(R.id.dynamic_add);
Log.d("Thread:", Thread.currentThread().getName());
foot.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
Log.d("Thread:", Thread.currentThread().getName());
foot.setText("子线程1");
}
}).start();
}
});
Thread thread = new Thread(){
@Override
public void run() {
Log.d("Thread:", Thread.currentThread().getName());
foot.setText("子线程2");
}
};
thread.start();
}
如果什么
也不操作,text确实会变成“子线程2”,为什么呢?通过源码分析,对UI进行操作时是使用ViewRoot的checkThread方法检查当前线程,然而当我们创建Activ作创建,所以导致在子线程可以操UI。
这时如果我们点击一个TextView则会报错:
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
嗯。这才是我们要的结果。
Handler机制
handler是Android最常用的消息通信机制,其实真正的通信还要有MessageQueue(内部其实是个链表)和Looper,三者一起协作才是我们常用的Handler。
Looper使用LocalThread变量保存,此变量比较特殊作用域为线程。
当创建Handler时就会获取当前线程的Looper。
创建完成后,我们可以在任意线程使用Handler,当我们使用send或者post发送 信息的时候,消息会发送至创建handler的线程的MessageQueue中。
Looper会不断循环查询MQ中是否有新的消息,如果有则进行处理,如果没有则等待。
4.处理时首先查询是否有回调(post的参数Runnable),如果没有查询Handler是否有回调,如果为空,才交给handleMessage进行处理。
Handler handler = new Handler()
{
@Override
public void handleMessage(Message msg) {
Thread.currentThread().getName();
foot.setText("子线程1");
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
foot = (TextView) findViewById(R.id.dynamic_add);
foot.setText("主线程");
Log.d("Thread:", Thread.currentThread().getName());
foot.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
Thread.currentThread().getName();
Message message = new Message();
handler.sendMessage(message);
}
}).start();
}
});
}
当我们点击TextView时,TextView会变为子线程1。
记住一句话:Handler会将消息(Message)或者操作(Runnable)搬运至创建它的线程处理。