做了也快2年的android了,发现android的机制还不是很了解,这几天看了一下这方面的介绍,总结一下handler的用法和机制。
handler就是用来线程之间通信的,主线程与子线程。一般的用法是,子线程通知ui主线程的handler去刷新ui操作。最近遇到一些人,问能不能主线程去通知子线程的handler。
当然是可以的。贴一个例子
package cc.c; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.widget.TextView; /** * Demo描述: * * 示例步骤如下: * 1 子线程给子线程本身发送消息 * 2 收到1的消息后,子线程给主线程发送消息 * 3 收到2的消息后,主线程给子线程发送消息 * * 为实现子线程给自己本身发送消息,关键还是在于构造Handler时传入的Looper. * 在此就传入该子线程自己的Looper即调用Looper.myLooper(),代码如下: * Looper.prepare(); * mHandlerTest1=new HandlerTest1(Looper.myLooper()); * Looper.loop(); * * 所以当mHandlerTest1.sendMessage(message);发送消息时 * 当然是发送到了它自己的消息队列. * * 当子线程中收到自己发送的消息后,可继续发送消息到主线程.此时只要注意构造 * Handler时传入的Handler是主线程的Handler即可,即getMainLooper(). * 其余没啥可说的. * * * 在主线程处理消息后再发消息到子线程 * * * 其实这些线程间发送消息,没有什么;关键还是在于构造Handler时传入谁的Looper. * */ public class MainActivity extends Activity { private TextView mTextView; private HandlerTest1 mHandlerTest1; private HandlerTest2 mHandlerTest2; private int counter=0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); init(); } private void init() { mTextView = (TextView) findViewById(R.id.textView); //1 子线程发送消息给本身 new Thread() { public void run() { Looper.prepare(); mHandlerTest1=new HandlerTest1(Looper.myLooper()); Message message = new Message(); message.obj = "子线程发送的消息Hi~Hi"; mHandlerTest1.sendMessage(message); Looper.loop(); }; }.start(); } private class HandlerTest1 extends Handler { private HandlerTest1(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); System.out.println("子线程收到:" + msg.obj); //2 收到消息后可再发消息到主线程 mHandlerTest2=new HandlerTest2(getMainLooper()); Message message = new Message(); message.obj = "O(∩_∩)O"; mHandlerTest2.sendMessage(message); } } private class HandlerTest2 extends Handler { private HandlerTest2(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); mTextView.setText("在主线程中,收到子线程发来消息:" + msg.obj); //3 收到消息后再发消息到子线程 if (counter==0) { Message message = new Message(); message.obj = "主线程发送的消息Xi~Xi"; mHandlerTest1.sendMessage(message); counter++; } } } }
这个就很好的展示了,子线程主线程都是可以有handler,可以互相传递消息的。必须要明确的是handler必须要绑定一个looper。但是区别在于,子线程需要做
Looper.prepare();
Looper.loop();这两个方法,而主线程不需要。因为主线程在启动的时候会初始化looper,如下:
Android程序的运行入口点可以认为是android.app.ActivityThread类的main()方法(源码2.3.3):
public static final void main(String[] args) { // other codes... // 创建主线程循环 Looper.prepareMainLooper(); if (sMainThreadHandler == null) { sMainThreadHandler = new Handler(); } ActivityThread thread = new ActivityThread(); thread.attach(false); // other codes... // 进入当前线程(此时是主线程)消息循环 Looper.loop(); // other codes... thread.detach(); // other codes... }
所以可以看到,如果要有消息循环的话,线程中任何时候都必须要有初始化looper的过程,只不过主线程在启动的时候已经帮我们完成,而子线程需要自己去实现。(需要注意的是,如果我们在ui线程中new handler而不做绑定,那么默认的认为handler是绑定主线程的looper,所以我们就可以想到,ui线程中new handler也可以绑定子线程的looper,即handlerThread的用法)
另外一个是,handlerThread,参考下面的解释:
在上面的总结中指出,Android的线程分为有消息循环的线程和没有消息循环的线程,有消息循环的线程一般都会有一个Looper。事实上Android提供了一个封装好的带有looper的线程类,即为HandlerThread,具体可参见下面的代码:
public class HandlerThreadActivity extends Activity { private static final String TAG = "HandlerThreadActivity"; private HandlerThreadmHandlerThread; private MyHandler mMyHandler; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generatedmethod stub super.onCreate(savedInstanceState); TextView text = new TextView(this); text.setText("HandlerThreadActivity"); setContentView(text); Log.d(TAG, "The mainthread id = " + Thread.currentThread().getId()); //生成一个HandlerThread对象,实现了使用Looper来处理消息队列的功能, //这个类由Android应用程序框架提供 mHandlerThread = new HandlerThread("handler_thread"); //在使用HandlerThread的getLooper()方法之前,必须先调用该类的start(); mHandlerThread.start(); //即这个Handler是运行在mHandlerThread这个线程中 mMyHandler = new MyHandler(mHandlerThread.getLooper()); mMyHandler.sendEmptyMessage(1); } private class MyHandler extends Handler { public MyHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { Log.d(TAG, "MyHandler-->handleMessage-->threadid = " + Thread.currentThread().getId()); super.handleMessage(msg); } } }
可以看到在该段代码中,在子线程中有 mHandlerThread = new HandlerThread("handler_thread"),然后在主线程中的hanler是绑定该线程的loooper的,mMyHandler = new MyHandler(mHandlerThread.getLooper());
我的理解的话,HandlerThread与thread的区别不大,因为HandlerThread是继承自thread的,只不过HandlerThread提供了默认的Looper。
总结一下:
1、handler是android提供的一种消息循环机制,为多线程提供了很大的帮助,特别是异步获取数据然后刷新ui的操作。
2、handler与looper是共生的,一个线程只有一个looper,只不过有的线程已经做好了初始化looper的操作(ui线程,HandlerThread),而其他子线程需要自己做。
3、handler通过绑定特定线程的looper,可以实现在该线程中向某一个looper发送消息,就可以在这个handler中处理了。如子线程中通过
Looper.prepare();mHandlerTest1=new HandlerTest1(Looper.myLooper());绑定自己的looper,也可以mHandlerTest2=new HandlerTest2(getMainLooper());绑定ui的looper都是可以的,然后主线程中也棒子子线程的looper,就看你如何绑定哪个looper了。