Handler,Looper,MessageQueue的实现
所要用到的android源码路径:
ActivityThread源码路径:android-4.0.3_r1\frameworks\base\core\java\android\app\ActivityThread
Activity源码路径:android-4.0.3_r1\frameworks\base\core\java\android\app\Activity
Handler源码路径:android-4.0.3_r1\frameworks\base\core\java\android\os\Handler
Looper源码路径:android-4.0.3_r1\frameworks\base\core\java\android\os\Looper
Message源码路径:android-4.0.3_r1\frameworks\base\core\java\android\os\Message
MessageQueue源码路径:android-4.0.3_r1\frameworks\base\core\java\android\os\MessageQueue
我们从使用handler发送一条message到接收进行处理的这个过程来理解Handler,Looper,MessageQueue的实现,在Activity主线程中,会默认
创建一个Looper对象,在这个Looper类中会创建一个MessageQueue的消息队列,然后主线程会调用Looper的的loop()方法循环遍历这个消息队
列,如果有消息则会通过Handler对象将消息传递到handlerMessage方法中进行处理,如果Hanlder对象为空也就是没有创建Hanlder对象则会将
这条消息丢掉。那么消息的发送是怎样的呢?我们创建一个Handler对象,使用这个对象发送Message,其实是使用Looper对象传递进来的
MessageQueue,通过这个消息队列的引用将Message放进消息队列中,由于Looper会遍历这个队列,所以Handler对象发送msg,将其放进消
息队列,Looper遍历消息队列将消息取出,然后传递给Hanlder进行处理,这样一个消息的发送与接收就完成了。
首先我们根据Handler的构造函数来了解Handler的几种使用方法,从API中我们知道Handler有四个构造函数,分别是:
Handler()Handler(callback)Handler(looper)Handler(looper, callback)
一、不带参数的Handler()构造函数,其使用的是主线程默认的Looper对象以及MessageQueue
Handler handler2 = new Handler(){public void handleMessage(Message msg) {};};handler2.sendEmptyMessage(30);直接在Activity中new一个Handler对象,并且重载handlerMessage方法就能够实现Message的发送与接收。
二、Handler(callback)构造函数,带了一个Hanlder类中的一个Callable接口对象作为参数,看源码就能够很清楚知道,他的作用其实是将handlerMessage
方法给独立出去,也就是在Activity中如果handlerMessage中的代码量太多,使用这个构造函数去创建对象,就能够将handlerMessage方法不放在
Activity中。
public class MyHandler implements Handler.Callback{@Overridepublic boolean handleMessage(Message arg0) {return false;}}先实现Hanlder.Callback接口,丛杂handlerMessage方法,在这里进行消息的处理
MyHandler callback = new MyHandler();Handler handler3 = new Handler(callback);handler3.sendEmptyMessage(20);在Activity中创建Handler对象,将Callback对象作为参数传递进去,然后使用handler发送Message,就能够在MyHandler中接收消息进行处理。
三、Handler(looper)构造函数,带了一个自定义的Looper对象作为参数,所以我们只要自定义一个Looper,然后将该Looper对象传递进去就能够正常
的进行消息发送与接收。但是我们不必要真的去自定义一个Looper类,我们只需要继承android已经实现好的HandlerThread线程,就能够自定义一个
Looper类
public class MyThread extends HandlerThread{//HandlerThread类是android中已经继承Thread的类,他已经帮你实现了Looper对象的创建//所以如果我们在实现Handler时,需要自定义Looper对象,则直接继承此类就行。public MyThread(String name) {super(name);}@Overrideprotected void onLooperPrepared() {//这个方法是在Looper.loop()被调用前在线程HandlerThread的run方法中被调用//所以如果要在这之前做什么操作,就需要重载这个方法Log.i("MyThread", "onLooperPrepared");super.onLooperPrepared();}}
MyThread thread = new MyThread("thread");thread.start();Looper looper = thread.getLooper();Handler handler1 = new Handler(looper){public void handleMessage(Message msg) {}};handler1.sendEmptyMessage(10);
这样我们就能够使用自定义的Looper进行消息的发送与接收,而不必使用Activity帮我们已经创建好的默认的Looper对象。
四、Handler(looper, callback)构造函数,知道了前面三种构造函数之后,这种就能够很容易理解了:使用自定义Looper,将handlerMessage方法
从创建Handler对象的类中独立出去。
Handler的详细使用方法就介绍完了,接下来我们就来分析相关类的源码,来彻底了解其运作过程。
首先我们来看看Looper的实现过程,我们知道在创建一个Activity时,其主UI主线程ActivityThread中会默认创建一个Looper对象,那么这个对象是在
什么地方创建的呢?
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); Process.setArgV0("<pre-initialized>"); Looper.prepareMainLooper(); if (sMainThreadHandler == null) { sMainThreadHandler = new Handler(); } ActivityThread thread = new ActivityThread(); thread.attach(false); if (false) { Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread")); } Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); }
step1:从上面ActivityThread源码中我们可以看见,这个main方法是主线程的启动的地方,首先他调用了Looper的静态prepareMainLooper()方法:
public static void prepareMainLooper() { prepare(); setMainLooper(myLooper()); myLooper().mQueue.mQuitAllowed = false; }
public static void prepare() { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper()); }
private synchronized static void setMainLooper(Looper looper) { mMainLooper = looper; }
public static Looper myLooper() { return sThreadLocal.get(); }
private Looper() { mQueue = new MessageQueue(); mRun = true; mThread = Thread.currentThread(); }在上面源码中我们可以看出,prepareMainLooper方法中调用prepare()方法创建了一个Looper对象,并将这个Looper对象放进了ThreadLocal中,将
Looper对象放进ThreadLocal中的作用是,ThreadLocal会维护Looper对象中变量的副本。具体可以参考ThreadLocal的使用方法。然后调用myLooper
方法从ThreadLocal中获取Looper对象,并将其赋值给主线程Looper对象的引用。在Looper构造函数中我们可以看见,他创建了一个MessageQueue
对象,同时获取了Looper对象所在当前线程的引用。这样一个Looper对象便创建成功。
step2:然后判断主线程的Handler是否为空,如果为空则默认创建一个Handler对象,但是在源码中这个默认的Handler时候从来就没使用过,
估计是既然已经默认创建了Looper,那么也默认创建一个Handler对象。
step3: 创建主线程ActivityThread对象,然后调用loop()方法
public static void loop() { Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } MessageQueue queue = me.mQueue; Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity(); while (true) { Message msg = queue.next(); // might block if (msg != null) { if (msg.target == null) { // No target is a magic identifier for the quit message. return; } long wallStart = 0; long threadStart = 0; // 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); wallStart = SystemClock.currentTimeMicro(); threadStart = SystemClock.currentThreadTimeMicro(); } msg.target.dispatchMessage(msg); if (logging != null) { long wallTime = SystemClock.currentTimeMicro() - wallStart; long threadTime = SystemClock.currentThreadTimeMicro() - threadStart; logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); if (logging instanceof Profiler) { ((Profiler) logging).profile(msg, wallStart, wallTime, threadStart, threadTime); } } // 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(); } } }
在loop方法中,首先获取之前创建的Looper对象,MessageQueue对象,清除所有之前的访问标志,然后下面就是一个while死循环,在这个while循环
中,通过Message msg = queue.next()不停的从消息队列中获取Message,然后判断获取的Message是否为空,不为空,则判断这个Message的target
是否为空,通过了解Message源码我们知道,这个target其实就是一个Handler对象,也就是如果在没有创建Handler对象,则这个Message不进行处理
直接返回,继续去下一个Message。如果已经创建了Handler对象,则通过msg.target.dispatchMessage(msg)将从消息队列中获取的Message传递
到Handler中。
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
在dispatchMessage中将消息传递到handlerMessage(msg)中,这样handler便接收到了一个Message。
通过上面三步,当一个Activity启动时,其主线程ActivityThread创建成功后,会默认创建一个Looper对象,一个消息队列。同时会循环遍历这个消息
队列,而不会管Handler对象有没有创建。
下面我们来看Handler是怎样发送一个消息进消息队列的,首先了解Hanlder的初始化过程:
public Handler() { 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 = null; }
从Handler的构造函数中我们可以看到,通过Looper.myLooper()获取Looper对象的引用,通过mLooper.mQueue获取消息队列的引用。
接下来我们看发送消息的方法:
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); }
public boolean sendMessageAtTime(Message msg, long uptimeMillis) { boolean sent = false; MessageQueue queue = mQueue; if (queue != null) { msg.target = this; sent = queue.enqueueMessage(msg, uptimeMillis); } else { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); } return sent; }从上面源码可以看到,调用sendMessage其实是调用sendMessageDelayed方法,在sendMessageDelayed方法中调用了sendMessageAtTime方法
sendMessageAtTime才是最终发送Message的地方,在sendMessageAtTime中我们可以看到,首先判断消息队列的引用是否为空,不为空则调用
enqueueMessage方法将Message放进消息队列中。在这个方法中我们还可以看到通过msg.target = this,Message获取到了当前Handler对象的引用
final boolean enqueueMessage(Message msg, long when) { if (msg.isInUse()) { throw new AndroidRuntimeException(msg + " This message is already in use."); } if (msg.target == null && !mQuitAllowed) { throw new RuntimeException("Main thread not allowed to quit"); } final boolean needWake; synchronized (this) { if (mQuiting) { RuntimeException e = new RuntimeException( msg.target + " sending message to a Handler on a dead thread"); Log.w("MessageQueue", e.getMessage(), e); return false; } else if (msg.target == null) { mQuiting = true; } msg.when = when; //Log.d("MessageQueue", "Enqueing: " + msg); Message p = mMessages; if (p == null || when == 0 || when < p.when) { msg.next = p; mMessages = msg; needWake = mBlocked; // new head, might need to wake up } else { Message prev = null; while (p != null && p.when <= when) { prev = p; p = p.next; } msg.next = prev.next; prev.next = msg; needWake = false; // still waiting on head, no need to wake up } } if (needWake) { nativeWake(mPtr); } return true; }
要理解enqueueMessage源码,就必须结合Looper获取消息的方法来理解:
final Message next() { int pendingIdleHandlerCount = -1; // -1 only during first iteration int nextPollTimeoutMillis = 0; for (;;) { if (nextPollTimeoutMillis != 0) { Binder.flushPendingCommands(); } nativePollOnce(mPtr, nextPollTimeoutMillis); synchronized (this) { // Try to retrieve the next message. Return if found. final long now = SystemClock.uptimeMillis(); final Message msg = mMessages; if (msg != null) { final long when = msg.when; if (now >= when) { mBlocked = false; mMessages = msg.next; msg.next = null; if (false) Log.v("MessageQueue", "Returning message: " + msg); msg.markInUse(); return msg; } else { nextPollTimeoutMillis = (int) Math.min(when - now, Integer.MAX_VALUE); } } else { nextPollTimeoutMillis = -1; } // If first time, then get the number of idlers to run. if (pendingIdleHandlerCount < 0) { pendingIdleHandlerCount = mIdleHandlers.size(); } if (pendingIdleHandlerCount == 0) { // No idle handlers to run. Loop and wait some more. mBlocked = true; continue; } if (mPendingIdleHandlers == null) { mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)]; } mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers); } // Run the idle handlers. // We only ever reach this code block during the first iteration. for (int i = 0; i < pendingIdleHandlerCount; i++) { final IdleHandler idler = mPendingIdleHandlers[i]; mPendingIdleHandlers[i] = null; // release the reference to the handler boolean keep = false; try { keep = idler.queueIdle(); } catch (Throwable t) { Log.wtf("MessageQueue", "IdleHandler threw exception", t); } if (!keep) { synchronized (this) { mIdleHandlers.remove(idler); } } } // Reset the idle handler count to 0 so we do not run them again. pendingIdleHandlerCount = 0; // While calling an idle handler, a new message could have been delivered // so go back and look again for a pending message without waiting. nextPollTimeoutMillis = 0; } }
在enqueueMessage中我们看到,首先判断Message的target即所属的Handler对象是否为空,为空则抛出RuntimeException异常,然后定义了一个
final boolean needWake变量,注意他没有进行初始化,而且为final类型,表明一旦其被初始化后就无法再次进行更改了,然后就是一个同步块,在
这个同步块中,首先获取一个全局Message对象mMessages的引用,如果这个Message不是延迟性或者空的消息,那么将这个msg赋值给这个全局
的Message对象mMessages,并且将mBlocked赋值给needWake,在MessageQueue源码中,可以看见mBlocked定义时是没有初始化的,那么
在哪里初始化呢?这就要看next()方法了。
我们知道在主UI线程创建时,Looper对象就会创建,就会调用loop()方法,就会调用next()方法循环遍历消息队列,由于一开始消息队列为空,所以
msg一定为空,执行的只是下面这段代码:
if (pendingIdleHandlerCount < 0) { pendingIdleHandlerCount = mIdleHandlers.size(); } if (pendingIdleHandlerCount == 0) { // No idle handlers to run. Loop and wait some more. mBlocked = true; continue; }从这里就能够看见,mBlocked一开始是初始化为true的,所以在同步方法块执行完毕后,会调用nativeWake方法。在next()方法中可以看见,其消息
操作的逻辑也是一个同步方法块,而且注意到了没有?他操作的Message不是从什么队列中获取的,其实操作的就是那个全局的Message对象
mMessages,并且从MessageQueue的其他removeMessages等方法可以看到,所有操作全局对象mMessages都是在方法同步块中的,所以我们
就应该能够明白了MessageQueue不是用什么消息队列来保存Message的,而只是使用一个全局的mMessages来保存的,每次Looper循环遍历的
都是mMessages对象,获取到之后然后将这个对象置为空,如果next()在调用,则其他方法调用处于阻塞状态,如果enqueueMessage处于调用中
则其他调用的方法处于阻塞中,所以当有多个线程同时调用同一个Handler对象发送Message时,其中只有一个线程调用的方法是处于运行状态的,
其他线程的调用是处于阻塞状态的,为什么android会这样进行处理呢?我觉得这么处理的原因是以时间换取空间,Handler发送消息的逻辑是相对
简单的,没有什么业务逻辑,也就是所需获取执行的时间是非常短的,而且不会出现很多线程同时使用同一个Handler来发送Message。
所以到这里我们就明白了MessageQueue的实现机制了:
1、MessageQueue不是什么消息队列,没有使用到队列,其使用的是一个全局对象来进行消息接收与发送
2、MessageQueue中所有的消息操作方法都是同步块的,当有一个方法被执行时,其他方法是处于阻塞状态的。
3、如果我们同时开启非常多的线程使用同一Handler发送消息或者移除消息,那么sendMessage(msg)不会立即返回结果的。
4、在多个线程中不要大量使用Handler来操作Message。他只适合于少量线程中进行使用。
这样Handler的消息发送以及Looper的消息获取就都剖析完了。Handler,Looper,MessageQueue的实现也就完全讲完了。
总结:
在我们创建一个Activity时,会自动创建一个Looper对象,并且在Looper的构造方法中会创建一个MessageQueue的对象,当Activity的主线程启动
时,会调用Looper的loop()方法循环检查MessageQueue中的全局对象mMessages是否为空,如果不为空则会调用相应Handler的
dispatchMessage方法,将这个消息传递到Handler中的handleMessage方法中进行处理。当我们创建一个Handler对象,使用这个Handler对象
发送消息时,最终调用的是MessageQueue中的enqueueMessage,消息的所有的操作,如:发送,移除,遍历都是在MessageQueue中进行
操作的,这也对应了面向对象的及迪米特法则,也就是所有该类的职责应该就在该类中完成,尽量少于外界进行联系。消息的处理是单个操作的
当一个消息在发送时,其他消息的发送是处于阻塞状态,由于消息操作的业务逻辑简单,所以不必过于关注消息操作的延时性,但是不应在大量
线程中使用Handler进行消息传递。
更多相关文章
- Android 获取控件宽高的3种方法
- Android中创建与几种解析xml的方法!
- Android当方法总数超过64K时(Android Studio)
- android ViewPager 使用方法
- Android 方法数超过64k限制的解决办法
- android的Services生命周期和使用方法
- Android onClick事件三种实现方法
- android学习——android 常见的错误 和 解决方法
- Android详细的对话框AlertDialog.Builder使用方法