Android-源码解析Handler&Looper
来源:互联网 发布:n9软件网 编辑:程序博客网 时间:2024/05/23 11:28
Handler是可以用来发送消息,或者一个Runable;消息/Runable可以在指定的线程(由Handler中的Looper决定)中接受/执行;
MessageQueue:消息队列,用来存放消息的
Looper:用来循环遍历消息队列中的消息,并负责消息的分发
我们看看使用Handler常用示例代码(如下
public class TestActivity extends Activity { private Handler mHandler = new Handler(){ @Override public void handleMessage(Message msg) { switch (msg.what) { case caseA: doSomeThingA(); break; case caseB; doSomeThingB(); break; default: break; } } }; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); sendMessage(); } private void sendMessage() { Message msg = Message.obtain(); msg.what = caseA; msg.obj = data; mHandler.sendMessage(msg); }}
我们可以看到mHandler变量作为成员变量,覆写了handleMessage方法,且是通过无参构造器创建出来的;
在onCreate方法调用了sendMessage方法,这样消息最终被传送到handlerMessage中;下面我们结合Handler部分源码看看消息是如何一步一步到达Handler的handleMessage方法里的。
TestActivity类中的sendMessage方法中发送消息后,调用了mHandler.sendMessage(msg),也就是如下代码,
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) { 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);}
我们从上述源码可以看到,handler发送的消息最终是把消息放到消息队列中,之后就没做任何事情了,那么问题来了
那么消息队列是在什么时候创建?
其实每个Looper都包含一个消息队列成员,而消息队列也是在Looper构造器时被创建;
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread();}
- 最终消息是如何分发到handlerMessage中?
我们看到Handler类中包含了Looper 和 消息队列成员变量,它们都是在构造器中被赋值(见下面Handler类部分源码)
/** * Default constructor associates this handler with the {@link Looper} for the * current thread. * * If this thread does not have a looper, this handler won't be able to receive messages * so an exception is thrown. */ public Handler() { this(null, false); }/** * Use the {@link Looper} for the current thread with the specified callback interface * and set whether the handler should be asynchronous. * * Handlers are synchronous by default unless this constructor is used to make * one that is strictly asynchronous. * * Asynchronous messages represent interrupts or events that do not require global ordering * with respect to synchronous messages. Asynchronous messages are not subject to * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}. * * @param callback The callback interface in which to handle messages, or null. * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for * each {@link Message} that is sent to it or {@link Runnable} that is posted to it. * * @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()); } } //获取当前线程的Looper对象 mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } //从Looper对象中获取消息队列 mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async; }
因为示例代码中Handler对象是在UI线程中创建,而系统在初始化时会自动调用Looper.prepareMainLooper方法,该方法帮我们创建好了主线程的Looper对象(所以在UI线程中我们不需要主动调用Looper.prepareMainLooper去创建Looper对象);创建Looper对象后会启用loop方法,它会不断循环读取消息队列的消息。
我们看下Looper源码:
package android.os;import android.annotation.NonNull;import android.annotation.Nullable;import android.util.Log;import android.util.Printer;/** * Class used to run a message loop for a thread. Threads by default do * not have a message loop associated with them; to create one, call * {@link #prepare} in the thread that is to run the loop, and then * {@link #loop} to have it process messages until the loop is stopped. * * <p>Most interaction with a message loop is through the * {@link Handler} class. * * <p>This is a typical example of the implementation of a Looper thread, * using the separation of {@link #prepare} and {@link #loop} to create an * initial Handler to communicate with the Looper. * * <pre> * class LooperThread extends Thread { * public Handler mHandler; * * public void run() { * Looper.prepare(); * * mHandler = new Handler() { * public void handleMessage(Message msg) { * // process incoming messages here * } * }; * * Looper.loop(); * } * }</pre> */public final class Looper { /* * API Implementation Note: * * This class contains the code required to set up and manage an event loop * based on MessageQueue. APIs that affect the state of the queue should be * defined on MessageQueue or Handler rather than on Looper itself. For example, * idle handlers and sync barriers are defined on the queue whereas preparing the * thread, looping, and quitting are defined on the 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>(); private static Looper sMainLooper; // guarded by Looper.class final MessageQueue mQueue; final Thread mThread; private Printer mLogging; /** 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"); } 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(); } } /** * Returns the application's main looper, which lives in the main thread of the application. */ public static Looper getMainLooper() { synchronized (Looper.class) { return sMainLooper; } } /** * Run the message queue in this thread. Be sure to call * {@link #quit()} to end the 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); } //target其实就是Handler,此处就是将消息传递到Handler中dispatchMessage方法中 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(); } } /** * 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(); } /** * Return the {@link MessageQueue} object associated with the current * thread. This must be called from a thread running a Looper, or a * NullPointerException will be thrown. */ public static @NonNull MessageQueue myQueue() { return myLooper().mQueue; } private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }}
我们可以看到上述代码中loop方法,其内部就是不断从消息队列中取消息,最终调用msg.target.dispatchMessage(msg);这里的target其实就是handler对象,也就是Handler的dispatchMessage方法;那么dispatchMessage内部是怎么实现?(看下面源码)
/** * Handle system messages here. */ public void dispatchMessage(Message msg) { if (msg.callback != null) { //如果Message中的Runnable不空,直接调用Message的Runable.run方法 handleCallback(msg); } else { //如果Handler中构造器传入了CallBack不为空 if (mCallback != null) { //如果CallBack不为空且handleMessage返回为true,直接返回(不执行handleMessage方法了) if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } } private static void handleCallback(Message message) { message.callback.run(); } public interface Callback { public boolean handleMessage(Message msg); }
我们的示例代码中发送的message的callback没有赋值所以为null,且我们的mHandler是无参构造的所以mCallback其实也是为空,所以最终执行到Handler的handleMessage方法;整个大体流程就是这样;
我们可以看到其实dispatchMessage方法运行在哪个线程其实是由Looper.loop决定的,至此整个流程逐渐清晰明朗起来了
梳理下流程:
通过Looper&Handler来达到线程间通讯
上面示例代码演示消息最终在UI线程被消费处理掉,如果要将一个消息/Runable传递给一个线程我们该如何做呢?我么可以这样做
class LooperThread extends Thread { private Handler mHandler; @Override public void run() { super.run(); //为当前线程创建一个Looper对象 Looper.prepare(); //handler会获取当前线程绑定的Looper对象 mHandler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); } }; //循环分发消息队列中的消息 Looper.loop(); } }
首先定义一个LooperThread,我们覆写run方法,并对该线程绑定一个Looper对象和一个Handler对象,这样在外部我们可以通过Handler对象将消息/Runable交给Handler的handlerMessage处理了;这样就达到了其他线程消息交给此线程处理目的,这其实就实现了线程间通讯了。
- Android-源码解析Handler&Looper
- Android Looper、Handler、Message源码解析
- android looper ,handler 解析
- Handler,message,Looper源码解析
- Handler Looper MessageQueue源码解析
- Handler、Looper、Message源码解析
- Looper Handler MessageQueue源码解析
- 深入源码解析Android中的Handler,Message,MessageQueue,Looper
- 深入源码解析Android中的Handler,Message,MessageQueue,Looper
- 深入源码解析Android中的Handler,Message,MessageQueue,Looper
- Android消息机制Handler,MessageQueue,Looper源码解析
- 深入源码解析Android中的Handler,Message,MessageQueue,Looper
- 深入源码解析Android中的Handler,Message,MessageQueue,Looper
- Android消息队列源码解析(Handler、Looper、Message、MessageQueue)
- Android源码:Handler, Looper和MessageQueue实现解析
- android Handler & Looper 源码解读
- Handler源码解析二------- Looper源码
- Android源码解析--Looper
- java.lang.IllegalStateException: Fatal Exception thrown on Scheduler.Worker thread.
- freeRTOS学习之xTaskCreat
- win32(5)--Windows菜单
- 减小ipa体积
- MATLAB 函数fspecial支持的空间滤波器
- Android-源码解析Handler&Looper
- Linux下SVN使用笔记
- Mysql5.7.18Zip安装配置
- mysql之 mysql 5.6不停机主从搭建(一主一从基于日志点复制)
- c# 之委托 匿名函数 lamada表达式
- C语言的#运算符
- php实现非对称加密
- Android平台HttpGet、HttpPost请求实例
- C指针操作(一)