Handler Looper MessageQueue Thread HandlerThread IntentService 的简单解析
这几个类应该是Android 很基础也很重要的几个类了。可以用这几个类做很多有意思的东西,
比如
Handler 类解析
Handler 一般作为消息的接收者的角色,接收某个线程发出的 Message 并处理。那 Handler 是如何接收以及如何处理 Message 的呢?我们先看下该类的构造方法。
public Handler() { // 构造方法 1
this(null, false);
}
public Handler(Callback callback, boolean async) { // 构造方法 2
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;
}
我们一般都是通过 new Handler()
这样的方式来创建一个 Handler , 通过上面的构造方法,我们可以得知,这种方式最终调用了构造方法 2 来构造一个 Handler ,而构造方法 2 里面最终执行了以下的关键代码。
// 获取和当前线程绑定的 Looper
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
// 拿到当前线程 looper 的 mQueue
mQueue = mLooper.mQueue;
// 持有回调方法,回调方法会在 dispatchMessage 方法里面用到
mCallback = callback;
mAsynchronous = async;
查看 Handler 的源码,你会发现还有一个构造方法
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
从这个构造方法来看,直接是给 mLooper
、mCalback
和 mAsynchronous
赋值。看着似乎和上面的 2 个构造方法没有特别多的区别,仔细想想区别还是蛮大,最大个一个区别应该是对 mLooper 赋值了,前 2 个构造方法没法直接指定 mLooper 绑定的线程,在哪个线程初始化的,mLooper 就是哪个线程绑定的 Looper , 而最后的一个构造方法是可以指定 mLooper 的,即你可以随意指定一个线程的 Looper , 包括 UI 线程的。
Handler 构造完成后,我们一般是发送消息,然后接收到消息后处理消息,我们先看看 Handler 里我们常用的发送消息的方法
public final boolean post(Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
public final boolean sendMessageDelayed(Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
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);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
从上面的代码可以看到,大概的一个流程是这样的,首先是创建了一个 Message ,这个 Message 携带了一些信息, what 、 obj 和 callback 等。这个 Message 最终被添加到了这个 Handler 的 mQueue
里面。而这个 mQueue
是 mLooper
来负责管理的。所以 Message 发出去后,后面是如何运行的,我们需要去查阅 Looper 的代码了。
Looper 类解析
Looper 这个类的内容并不多,我们还是从构造方法入手来看
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
可以看到,是一个私有的构造方法,所以一般我们不能通过 new
的方式来创建一个 Looper 对象。既然无法直接 new 一个对象,那肯定会有其他方式可以获取一个 Looper ,要不然我们如何拿到 Looper 呢。再次查阅源码我们发现下面的代码
/**
* Returns the application's main looper, which lives in the main thread of the application.
*/
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
只有这2个方法可以获取到一个 Looper ,从代码里面看到,基本都是返回某个对象,还是没看到 new Looper 类似的代码,继续看代码我们发现了下面的几个方法
/** Initialize the current thread as a looper.
* This gives you a chance to create handlers that then reference
* this looper, before actually starting the loop. Be sure to call
* {@link #loop()} after calling this method, and end it by calling
* {@link #quit()}.
*/
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
// new 了一个 Looper 并和当前线程绑定
sThreadLocal.set(new Looper(quitAllowed));
}
/**
* Initialize the current thread as a looper, marking it as an
* application's main looper. The main looper for your application
* is created by the Android environment, so you should never need
* to call this function yourself. See also: {@link #prepare()}
*/
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
可以看到这几个方法大概的意思是如果当前线程没有绑定 Looper,那么就新建一个 Looper 和当前线程绑定。
Looper 类里面的代码差不多都介绍了,还剩下最关键的一个方法,就是下面的方法。
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
public static void loop() {
// 获取当前线程的 Looper
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();
// 一个死循环,不停从 queue 里面拿出 Message,然后处理
// 如果没有 Message 了,就等待
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
msg.target.dispatchMessage(msg);
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycleUnchecked();
}
}
通过代码可以看到,这个方法的主要做了一件事,就是不停从 queue
里面拿出 Message
,然后处理,如果没有 Message
了,就等待。
单独看 Looper
的源码,好像并不是特别的清晰,我们找个场景串一下,更好理解。我们看下 App 的启动,在 ActivityThread
这个类里面有个 main
方法,这个方法可以只关注下面的2行代码
public static void main(String[] args) {
...
Looper.prepareMainLooper();
...
Looper.loop();
}
从代码可以看到先是调用了 Looper.prepareMainLooper()
方法将 UI 线程和 Looper 绑定,接着调用了 Looper.loop()
方法从当前线程绑定的 Looper 的 mQueue 里面拿消息处理。这也告诉我们,如果需要在一个线程里面使用 Handler,需要先调用 Looper.prepare()
方法,接着调用 Looper.loop()
,才可以使用 Handler。
在 Looper.loop()
方法里面有一行代码很关键
msg.target.dispatchMessage(msg);
这行代码的意思是,取到 msg
的时候会交给 msg
的 target
去 dispatchMessage
这个 msg
。从前面的 enqueueMessage
方法我们得知 Message
的 target
正是发送 Message
的 Handler
。那我们看看 Handler
的 dispatchMessage
方法。
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
private static void handleCallback(Message message) {
message.callback.run();
}
这段代码告诉我们,会先去看看 Message
的 callback
是否为空,如果不为空,交给 callback
处理。如果为空,那么再去看看 Handler
的 mCallback
是否为空,不为空交个 mCallback
处理,如果为空的话,就交个 Handler
的 handlerMessage
方法去处理,这个方法大家应该比较熟悉了。
从前面的 post
调用分析,我们知道 msg.callback
其实就是那个 post
的 Runnablle
,所以 post
的 runnable
最终会在当前线程绑定的 looper
从消息队列中取到消息的时候去处理。而处理的线程就是 这个 looper
所在的线程里,如果这个 looper
是主线程,那么就不能做耗时操作。
Handler 还有一个常用的方法是
public final boolean sendMessage(Message msg) {
return sendMessageDelayed(msg, 0);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
看下来其实和 post 方法并没有太大区别,只是 Message
是我们自己创建的,不一定会设置 callback
值,如果设置了 callback
的值,调用的顺序和 post
一致了。
到这里, Handler 和 Looper 的解析大概就完成了。先调用 Looper 的 prepare() 方法和 loop() 方法,让 Looper 的框架跑起来,不停从 mQueue 里面取消息处理。然后是新建一个 Handler 和 Looper 绑定,方便后续发送消息到 Looper 的 mQueue 里面,消息发送到了 Looper 的 mQueue 里面后, Looper 最终会取出这个消息,然后处理这个消息。
HandlerThread
这个也是一个比较特殊的类。从类名初步看是一个线程,先看看这个类的主要代码。
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
//··· 忽略其他代码
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
}
仔细观察,发现里面有一个 mLooper 属性,还有一个 getLooper
方法。结合前面的 Handler
的分析,我们在创建一个 Handler 的时候可以传入一个 Looper
,并且这个 Handler
发送的 Message
的处理是在和 Looper
绑定的线程下面的。如果我们想利用 Handler
处理耗时任务,那我们可以用 HandlerThread
来处理。
IntentService
之所以提这个类是因为用到了 HandlerThread ,而且也是一个比较有用的类,从类的名字我们可以知道,这个是一个 Service , Service 一般用于处理后台任务。
我们先简单看下源码
public abstract class IntentService extends Service {
...
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
/**
* Creates an IntentService. Invoked by your subclass's constructor.
*
* @param name Used to name the worker thread, important only for debugging.
*/
public IntentService(String name) {
super();
mName = name;
}
...
@Override
public void onCreate() {
// TODO: It would be nice to have an option to hold a partial wakelock
// during processing, and to have a static startService(Context, Intent)
// method that would launch the service & hand off a wakelock.
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public void onStart(Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
...
/**
* This method is invoked on the worker thread with a request to process.
* Only one Intent is processed at a time, but the processing happens on a
* worker thread that runs independently from other application logic.
* So, if this code takes a long time, it will hold up other requests to
* the same IntentService, but it will not hold up anything else.
* When all requests have been handled, the IntentService stops itself,
* so you should not call {@link #stopSelf}.
*
* @param intent The value passed to {@link
* android.content.Context#startService(Intent)}.
*/
@WorkerThread
protected abstract void onHandleIntent(Intent intent);
}
首先,IntentService 是一个抽象类,不能直接使用,子类需要实现 onHandleIntent
才可以。
然后我看启动过程,在 onCreate()
方法里面创建了一个 HandlerThread
和一个 ServiceHandler
,同时将 HandlerThread
的 Looper
和 ServiceHandler
绑定,我们调用 startService()
方法后,最终 onStart
方法被调用,可以看到这个这个 intent
最终交给了 ServiceHandler 的 handleMessage 方法
处理, 在 handleMessage
方法里面给了 onHandleIntent
去处理。
仔细思考,由于 Looper
处理消息是一个一个的处理,所以 IntentService
也是一个一个地处理事件,并且事件处理完后会尝试关闭,节省资源,简化代码。