Looper和Handler的分析
Posted zhenjie_chang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Looper和Handler的分析相关的知识,希望对你有一定的参考价值。
在写程序的时候我们经常用到handler来进行通信,但是却不太理解Handler的通信机制,今天有机会看了一下,下面来分析一下handler的机制。
看到Looper和handler就想起以前写程序的时候常用的几个方法Looper.prepare(),Looper.loop(),Handler的handleMessage(),就先从Looper.prepare()来分析:
以下是Looper.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));
这个方法非常简单,但是其中有一个sThreadLocal,不知道它是做什么的,那我们来找一下它的定义:
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
在Looper中只是new了一个ThreadLocal的对象,这个ThreadLocal是什么呢?网上查了一下
说ThreadLocal使得各线程能够保持各自独立的一个对象,并不是通过ThreadLocal.set()来实现的,而是通过每个线程中的new 对象 的操作来创建的对象,每个线程创建一个,不是什么对象的拷贝或副本。通过ThreadLocal.set()将这个新创建的对象的引用保存到各线程的自己的一个map中,每个线程都有这样一个map,执行ThreadLocal.get()时,各线程从自己的map中取出放进去的对象,因此取出来的是各自自己线程中的对象,ThreadLocal实例是作为map的key来使用的。
看了以下这个就明白了这段代码的作用了吧1:如果本线程中已经保存过Looper对象,就报了个“每个线程中只能有一个looper对象”的异常。2:创建一个Looper对象,并保存在ThreadLocal中。然后我们看一下Looper的构造方法:
private Looper(boolean quitAllowed)
mQueue = new MessageQueue(quitAllowed);
mRun = true;
mThread = Thread.currentThread();
这个方法也很简单,只有两步1:创建一个MessageQueue对象。2:得到本线程的对象。
到目前为止Looper.prepare()方法已经执行完成,它都做了些什么呢?
1:创建一个Looper()对象,存入到ThreadLocal线程的局部变量中,每个线程只有一份。
2:创建了一个MessageQueue对象,用来保存消息
接着我们来分析一下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 (;;)
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.recycle();
这个方法中其实有用的信息也就几行,下面我们首先来看第一行
final Looper me = myLooper()
使用myLooper()方法得到了一个Looper()对象。其实就是从本线程的局部变量中将Looper对象拿出来。
public static Looper myLooper()
return sThreadLocal.get();
得到Looper对象之后,然后又从Looper对象中拿出来MessageQueue.最终调用for循环来遍历MessageQueue,从消息队列中拿出来待处理的消息。
msg.target.dispatchMessage(msg);
然后我们再来看一下msg.target是什么?为什么要调用这个方法呢?在Message类的内部我们发现target的类型为Handler,所以这里应该是调用Handler的dispatchMessage()方法。
public void dispatchMessage(Message msg)
if (msg.callback != null)
handleCallback(msg);
else
if (mCallback != null)
if (mCallback.handleMessage(msg))
return;
handleMessage(msg);
上面这段代码是Handler中的dispatchMessage()方法。可以看出在dispatchMessage()到处理流程。优先执行msg的回调方法,然后在执行handler的回调方法,以上方法都没有的话,最后执行handleMessage();看到handleMessage()方法是不是很熟悉呢?这handler类中找到handleMessage()方法,但是 他是一个空方法,需要我们自己实现,这就是我们写程序的时候最常用的handleMessage()方法了,来处理handler发送过来的消息。
消息的处理流程大概就是以上的分析,但是我们还是没有分析handler的sendMessage()方法,别着急,下面我们就来看一下Handler的内部结构。
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;
这是Handler的构造方法,我们在其中来找到我们需要的信息,第一mLooper=Looper.myLooper(); 我们分析过Looper了,可知道这一行来得到线程局部变量ThreadLocal中保存的Looper对象,mQueue = mLooper.mQueue(); 这一句来得到Looper对象中的消息队列。
然后我们在分析Handler的sendMessage()方法。
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);
还是没有要的信息,那我们就在看一下sendMessageAtTime()方法。
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);
这里来判断从Looper对象中拿到的消息队列是不是null,如果不是null,就执行enqueueMessage方法,这个方法一定就是把handler发送的消息放入消息队列的方法了。
到此为止,Handler和Looper发送和处理消息的流程我们就简单的分析完了。简单的说它的工作流程分为几步:
1.handler向本线程的消息队列中放入要处理的消息
2.Looper循环读取消息队列的消息,然后分配给相应的handler处理,Handler为构造Message是传入的Handler
3.Handler的handleMessage方法来处理相应的消息
由以上分析可知,handler和Looper都是使用的同一个消息队列。只有执行过Looper.prepare()和Looper.loop()方法的线程才可以使用Handler来发送处理消息。我们知道UI线程是可以使用Handler来发送消息的,那UI主线程一定也执行过这两个方法了。我们来看一看代码:
public static void main(String[] args)
SamplingProfilerIntegration.start();
// CloseGuard defaults to true and can be quite spammy. We
// disable it here, but selectively enable it later (via
// StrictMode) on debug builds, but using DropBox, not logs.
CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
// Set the reporter for event logging in libcore
EventLogger.setReporter(new EventLoggingReporter());
Security.addProvider(new androidKeyStoreProvider());
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null)
sMainThreadHandler = thread.getHandler();
AsyncTask.init();
if (false)
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
只不过主线程中执行的是Looper.prepareMailLooper(),其实它和Looper.prepare()方法的作用是一样的。
以上是关于Looper和Handler的分析的主要内容,如果未能解决你的问题,请参考以下文章
android的消息处理机制(图+源码分析)——Looper,Handler,Message
android的消息处理机制(图+源码分析)——Looper,Handler,Message
[Android源代码分析]Android消息机制,Handler,Message,Looper,MessageQueue