Thread、Handler与HandlerThread

今天在看Android源码的时候,,看到了大量Handler的应用,和我以前开发APP的时候使用Handler的方法不太一样,所以花了一些时间来研究Handler。这里简单的记录一下。

Handler、Thread与Loop

一个线程(Thread)“可以”存在一个消息队列(MessageQueue)和一个消息循环(MessageQueue)。但是在线程创建的时候,这两个东西是不存在的。需要用Looper.prepare()来创建消息队列,用Looper.loop()来启动消息的循环。请看下面的这个例子。

public class LooperThread extends Thread {public Handler mHandler;public void run(){Looper.prepare(); // 创建消息队列。mHandler = new Handler(){@Overridepublic void handlerMessage(Message msg){}};Looper.loop(); // 启动消息循环。这个要在run()函数的最后调用。}}

这个例子是在一个自定义的线程中创建了Looper并让消息队列循环跑起来。那么这样一个有Looper和MessageQueue的线程和Handler的关系是怎么样的呢?在Handler初始化的时候,如果使用的是无参的构造函数,那么它将获取当前线程的Looper和MessageQueue,如果初始化的时候传入了Looper,那么Handler将获取这个Looper以及对应的MessageQueue。换句话说,传入的是哪个线程的Looper,Handler就属于哪个线程。所以一个Handler只能属于一个Thread。

另外一句话就是一个线程却可以拥有多个Handler。这句话我在很多个地方都看到了,但是因为没有仔细的去分析源代码,所以没有找到这句话的来源,但是我可以给出一个例子,说明一个线程是可以拥有多个Handler的,在消息的传递过程中不会乱。例子如下:

// 发送消息一般有如下两种方法 Message msg = new Message();msg.what = 1;handler.sendMessage(msg);Message msg = handler.obtainMessage();msg.what = 1;msg.sendToTarget();

很明显,第一种方法产生的msg将传递给调用sendMessage()方法的handler,第二种方法产生的msg将传递给调用obtainMessage()方法的handler。

说一句题外话,在Android APP开发中,因为更新UI只能在主线程中进行,所以经常会在主线程中定义Handler,子线程通过向Handler发送消息,由Handler对象的handleMessage()函数来更新UI。在这种情况下,并不需要显式地调用Looper.prepare()和Looper.loop()。这其中的原因就是在UI的ActivityThread中已经调用过了这两个函数,也就是说,每一个APP的主线程都默认定义好了Looper和MessageQueue,所以直接用就好了。有兴趣的朋友可以研究一下ActivityThread.java这个文件。

Handler的构造函数

Android源码中Handler的构造函数有好几个,分别如下:

public Handler() {this(null, false);}public Handler(Callback callback) {this(callback, false);}public Handler(Looper looper) {this(looper, null, false);}public Handler(Looper looper, Callback callback) {this(looper, callback, false);}/** * @hide */public Handler(boolean async) {this(null, async);}/** * @hide */public Handler(Callback callback, boolean async) {if (FIND_POTENTIAL_LEAKS) {final Class<? extends Handler> klass = getClass();if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&(klass.getModifiers() & Modifier.STATIC) == 0) {Log.w(TAG, “The following Handler class should be static or leaks might occur: ” +klass.getCanonicalName());}}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;}/** * @hide */public Handler(Looper looper, Callback callback, boolean async) {mLooper = looper;mQueue = looper.mQueue;mCallback = callback;mAsynchronous = async;}

我抽几个常用的简单分析一下。首先是默认构造函数:

public Handler() {this(null, false);}

可见它实际上将调用下面的构造函数:

public Handler(Callback callback, boolean async) {if (FIND_POTENTIAL_LEAKS) {final Class<? extends Handler> klass = getClass();if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&(klass.getModifiers() & Modifier.STATIC) == 0) {Log.w(TAG, “The following Handler class should be static or leaks might occur: ” +klass.getCanonicalName());}}// 从这里开始分析。mLooper = Looper.myLooper(); // 获取当前线程的Looper。if (mLooper == null) {throw new RuntimeException(“Can’t create handler inside thread that has not called Looper.prepare()”);}mQueue = mLooper.mQueue; // 获取当前线程的MessageQueue。mCallback = callback;mAsynchronous = async;}

首先获取当前线程的Looper,然后通过这个Looper获取当前线程的MessageQueue。这样,线程的Looper和MessageQueue将交由Handler处理。

另外一个常用的构造函数如下:

public Handler(Looper looper, Callback callback) {this(looper, callback, false);}

它将调用的构造函数如下:

public Handler(Looper looper, Callback callback, boolean async) {mLooper = looper;mQueue = looper.mQueue;mCallback = callback;mAsynchronous = async;}

这里的Handler对象将绑定传入的Looper并通过传入的Looper对象获取其MessageQueue。

HandlerThread

HandlerThread是谷歌制造出来专为异步处理各种消息的线程,借助于它,我们可以非常方便的设计出异步处理程序。为什么方便?因为它默认的run()函数里已经构建好了Looper和MessageQueue。

public void run() {mTid = Process.myTid();Looper.prepare(); // 就是这里synchronized (this) {mLooper = Looper.myLooper();notifyAll();}Process.setThreadPriority(mPriority);onLooperPrepared();Looper.loop(); // 还有这里mTid = -1;}贪婪是最真实的贫穷,满足是最真实的财富

Thread、Handler与HandlerThread

相关文章:

你感兴趣的文章:

标签云: