前言:我们知道Android是基于Dalvik虚拟机的,Android所有组件都是在一个进程当中的,而这个进程当中有一个主线程,用来处理UI的更新,所以我们也叫做UI线程。为了用户体验,在Android4.0以后就不允许在主线程中做耗时操作。一切的耗时操作都放到了子线程中,那么子线程怎么通知界面进行更新呢?Android中有个常用的办法,就是通过Handler类来传递子线程到主线程的消息,从而通知主线程更新界面。那么主线程是否可以向子线程发送消息呢?
我们先尝试向子线程给主线程发送消息的方式在子线程中创建一个handler,接受来自UI线程的消息,代码如下:
public class MainActivity extends Activity { private Handler handler; private final int MESSAGE_TAG=0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); new myThread().start();//启动子线程 } public void sendMessageToThread(View view){ //主线程向子线程发送消息 String str="我是主线程发送过来的消息"; handler.obtainMessage(MESSAGE_TAG,str).sendToTarget(); } private class myThread extends Thread{ @Override public void run() { super.run(); handler=new Handler(){ @Override public void handleMessage(Message msg) { switch (msg.what){ case MESSAGE_TAG: Toast.makeText(MainActivity.this,"主线程发送给子线程的消息为:"+(String)msg.obj, Toast.LENGTH_SHORT).show(); break; } } }; } }; }
运行程序会报一下错误:
我们可以看到,在线程中不调用Looper.prepare()方法,是不能创建handler对象的。
可是我们在UI线程中也没有调用Looper.prepare()方法呀,为什么没有报错呢?
查看源码可以知道,主线程中有个ActivityThread类,程序的入口就是该类中的main()方法。main的源码如下:
分析源码可以知道,main()方法中调用prepareMain()为UI线程创建一个消息队列(MessageQueue),然后创建一个ActivityThread对象,在ActivityThread的初始化代码中会创建一个H(Handler)对象和一个ApplicationThread(Binder)对像。
我们可以看到Handler通过mLooper = Looper.myLooper();绑定到线程的当前Looper上去,同时Handler通过mQueue =mLooper.mQueue;获得线程的消息队列。此时,Handler就绑定到创建此Handler对象的线程的消息队列上了。
接着UI主线程调用Looper.loop()方法进入消息循环体,进入后就会不断地从消息队列中读取并处理消息。看看loop()的源码。
loop()方法中通过msg.next()获取下一条需要处理的消息。当msg!=null && msg.target!=null时,调用msg.target.dispatchMessage(msg)分发消息,分发完成之后就通过msg.recycle()回收消息。msg.target获取的就是绑定到当前消息队列上的handler。看看dispatchMessage(msg)方法。
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
通常我们在使用的时候,就会重写handler中的handleMessage(msg)方法来处理消息。
这样Handler+Looper+Message的机制就理清楚了。所以其实UI线程中也是有looper.prepare()和looper.loop()方法,只是main()方法已经做好了,但是我们自己new的子线程就需要我们自己调用这两个方法。主线程给子线程发送消息正确的写法为:
备注:此文章是本人查看了相关源码,也看了一些大牛们的博客之后的一点心得体会,主要是为了加强理解。谢谢那些无私奉献的博主们!!!!