Android系统中的视图组件并不是线程安全的,如果要更新视图,必须在主线程中更新,不可以在子线程中执行更新的操作。(子线程一般肩负起比较繁重的任务),所以引入了Handler和AsyncTask机制。
Handler机制
public class NewThread3 extends Activity {
public static final int UZI=0;
private Button btn;
private TextView text1;
private Handler handler=new Handler(){
public void handleMessage(Message msg) {
if(msg.what==UZI){
text1.setText("finally");
}
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text1 = (TextView) findViewById(R.id.text1);
btn = (Button) findViewById(R.id.btn1);
btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
new MyThread().start();
}
});
}
private class MyThread extends Thread {
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
//处理比较耗时的操作
Message msg=new Message();
msg.what=UZI;
handler.handleMessage(msg);
}
}
}
子线程处理繁重的任务,然后通过Handler传送Message通知主线程更新ui,主线程拿到message后再处理并更新ui。
Android的消息循环是针对线程的,每个线程都可以有自己的消息队列和消息循环。
Android系统中的Looper负责管理线程的消息队列和消息循环。通过Looper.myLooper()得到当前线程的Looper对象,通过Looper.getMainLooper()得到当前进程的主线程的Looper对象。
,一个线程可以存在一个消息队列和消息循环,特定线程的消息只能分发给本线程,不能跨线程和跨进程通讯。但是创建的工作线程默认是没有消息队列和消息循环的
所以需要用Looper.prepare()来创建消息队列,然后调用Looper.loop()进入消息循环
创建工作线程如下:
class MyThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// 处理收到的消息
}
};
Looper.loop();
}
}
此时工作线程也有自己的消息处理机制了;
***Ui线程,也就是主线程,系统会默认分配消息队列和消息循环
了解了上面Handler和loop的关系后,再来看一个Ui线程和工作线程间进行消息传递的例子。
public class MainActivity extends ActionBarActivity {
private int mCount = 0;
private Handler mHandlerThr = null;
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.d(null, ">>>>>>>>>>>>>UI# mHandler--handleMessage--msg.what="+msg.what);
//接收发送到UI线程的消息,然后向线程中的Handler发送msg 1。
mHandlerThr.sendEmptyMessage(1);
mCount++;
if (mCount >= 3) {
//由于mHandlerThr是在Child Thread创建,Looper手动死循环阻塞,所以需要quit。
mHandlerThr.getLooper().quit();
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();
}
@Override
protected void onStop() {
super.onStop();
//删除所有call与msg
mHandler.removeCallbacksAndMessages(null);
}
private void initData() {
Log.d(null, ">>>>>>>>>>>>>UI# begin start thread!!!");
new Thread() {
@Override
public void run() {
super.run();
Looper.prepare();
mHandlerThr = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.d(null, ">>>>>>>>>>>>>Child# mHandlerThr--handleMessage--msg.what=" + msg.what);
//接收发送到子线程的消息,然后向UI线程中的Handler发送msg 0。
mHandler.sendEmptyMessage(0);
}
};
Log.d(null, ">>>>>>>>>>>>>Child# begin start send msg!!!");
//Activity中启动Thread,在Thread结束前发送msg 0到UI Thread。
mHandler.sendEmptyMessage(0);
Looper.loop(); //不能在这个后面添加代码,程序是无法运行到这行之后的。
}
}.start();
}
}
运行结果如下:
>>>>>>>>>>>>>UI# begin start thread!!!
>>>>>>>>>>>>>Child# begin start send msg!!!
>>>>>>>>>>>>>UI# mHandler--handleMessage--msg.what=0
>>>>>>>>>>>>>Child# mHandlerThr--handleMessage--msg.what=1
>>>>>>>>>>>>>UI# mHandler--handleMessage--msg.what=0
>>>>>>>>>>>>>Child# mHandlerThr--handleMessage--msg.what=1
>>>>>>>>>>>>>UI# mHandler--handleMessage--msg.what=0
Handler与Looper实例化总结
在主线程中可以直接创建Handler对象,而在子线程中需要先调用Looper.prepare()才能创建Handler对象,否则运行抛出”Can’t create handler inside thread that has not called Looper.prepare()”异常信息。
每个线程中最多只能有一个Looper对象,否则抛出异常。
可以通过Looper.myLooper()获取当前线程的Looper实例,通过Looper.getMainLooper()获取主(UI)线程的Looper实例。
一个Looper只能对应了一个MessageQueue。
一个线程中只有一个Looper实例,一个MessageQueue实例,可以有多个Handler实例。
继续看看Handler消息收发机制源码
通过Handler发消息到消息队列
比较sendMessageAtTime()和sendMessageAtFrontOfQueue()方法
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
再看看sendMessageAtFrontOfQueue()方法
public final boolean sendMessageAtFrontOfQueue(Message msg) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, 0);
}
Handler发送消息实质就是把消息Message添加到MessageQueue消息队列中的过程而已。
既然消息都存入到了MessageQueue消息队列,当然要取出来消息吧,不然存半天有啥意义呢?我们知道MessageQueue的对象在Looper构造函数中实例化的;一个Looper对应一个MessageQueue,所以说Handler发送消息是通过Handler构造函数里拿到的Looper对象的成员MessageQueue的enqueueMessage方法将消息插入队列,也就是说出队列一定也与Handler和Looper和MessageQueue有关系。