大家在编写android项目的时候应该用到Handler了吧.
一般做法应该都是先在主线程中创建一个Handler实例
Handler handler = new Handler{
public void handleMessage(Message msg) {
//做相应处理
}
}
然后通过handler.sendMessage(Message msg)发送消息.
最后在handleMessage()回调中做相应的处理.
那么这里有几个疑问:什么是主线程?发送消息到哪里去了?handleMessage()为什么会被回调?
1.主线程也就是UI线程,所有的处理用户消息,以及绘制界面的工作都在该线程中完成的,UI线程是从ActivityThread运行的,
public static void main(String[] args) { ...... Looper.prepareMainLooper(); ...... Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); }
在frameworks/base/core/java/android/os/Looper.java中
public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); } }接着看prepare()函数:
private static void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(quitAllowed)); }
public class Looper { private static final String TAG = "Looper"; // sThreadLocal.get() will return null unless you've called prepare(). static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();........
一般一个应用程序都在一个进程中,所以ActivityThread类的main()函数只会执行一次,所以prepare()函数只会执行一次.
通过上面分析我们知道,每个线程通过prepareMainLooper()函数调用prepare()函数,设置一个Looper对象,那么它们保存的Looper对象是不相同的.
好了,继续看到主线程的Looper对象是如何构造的.sThreadLocal.set(new Looper(quitAllowed));
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mRun = true; mThread = Thread.currentThread(); }
这里就是给Looper对象创建了一个消息队列.
然后回到prepareMainLooper()函数,接着看sMainLooper = myLooper();
public static Looper myLooper() { return sThreadLocal.get(); }
ActivityThread类的main()函数里面的prepareMainLooper()函数做了两件事,第一是创建了一个MessageQueue(消息队列),第二是创建了一个Looper对象,一个线程只有一个Looper对象,因此只有一个MessageQueue(消息对象).
ActivityThread类的main()函数里面的另一个函数Looper.loop();
public static void loop() { final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } final MessageQueue queue = me.mQueue; // Make sure the identity of this thread is that of the local process, // and keep track of what that identity token actually is. Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity(); for (;;) {...这个函数的就是从主线程的Looper对象的消息队列中不断的读取和发送消息.一个死循环吧.
读取消息然后回调对应handler的handleMessage(Message msg) 方法.
上面的三个问题我们了解差不多,但是又有新的疑问,new Handler()发送消息就怎么就会发送到主线程的Looper对象里面的消息队列里面去呢??
好了,我们来看一下Handler的构造方法:
public Handler() { this(null, false); } public Handler(Callback callback, boolean async) { ... mLooper = Looper.myLooper();// if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async; }
这样一来我们也知道了,如果在一个线程中使用handler,那么该线程中必须创建了Looper对象.有了Looper对象也就有了消息队列(它在looper的构造方法里面创建).
这样线程称呼为异步消息线程.
总结一下:异步消息处理线程启动后会进入一个无限的循环体之中,每循环一次,从其内部的消息队列中取出一个消息,然后回调相应的消息处理函数,执行完成一个消息后则继续循环。若消息队列为空,线程则会阻塞等待.
android应用程序的主线程就这样一个异步消息线程.
那么除主线程外,我们自定义线程可不可定义成异步消息线程呢?当然可以,android提供了一个HandlerThread这个类
frameworks/base/core/java/android/os/HandlerThread.java
写一个线程MyThread 继承HandlerThread, 看它的run()方法
public void run() { mTid = Process.myTid(); Looper.prepare(); synchronized (this) { mLooper = Looper.myLooper(); notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); Looper.loop(); mTid = -1; }
public Handler(Looper looper) { this(looper, null, false); }没错,直接传入该线程的looper对象就可以该线程的looper对象怎么获取呢:
public Looper getLooper() { .... return mLooper; }
这样想要往这个线程发送消息,构建一个handler传入looper对象.
我们在项目用得最多的应该是往主线程发送更新UI的消息,因为更新UI必须要在主线程中,不然会报异常.