异步回调机制,也可以理解为线程间的消息机制。为了避免ANR,我们通常会把一些耗时操作(比如:网络请求、I/O操作、复杂计算等)放到子线程中去执行,而当子线程需要修改UI时则子线程需要通知主线程去完成修改UI的操作,则此时就需要我们使用Handler机制来完成子线程与主线程之间的通信。
尽管Message的构造器是公开的,但是获取Message对象的最好方法是调用Message.obtain()或者Handler.obtainMessage(), 这样是从一个可回收对象池中获取Message对象。
这两种方式都比直接new一个Message对象在性能上更优越.
handler的构造方法
Handler mHandler = new Handler();
@Deprecated public Handler() { this(null, false); }
获取当前Handler实例所在线程的Looper对象:mLooper = Looper.myLooper()
如果Looper不为空,则获取Looper的消息队列,赋值给Handler的成员变量mQueue:mQueue = mLooper.mQueue
可以设置Callback 来处理消息回调:mCallback = callback
Handler是消息的处理者,但是它并不是最终处理消息的那个大佬,它有且只能有一个上级领导,就是Looper,Handler是将消息上报给Looper(领导),然后排队等待,等Looper(领导)处理完消息了,就会通知Handler去领取消息,给Handler分配任务,Handler拿到消息后在自行往下分发,Handler只能听命与Looper(领导)。
public Handler(@Nullable 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 " + Thread.currentThread() + " that has not called Looper.prepare()"); } mQueue = mLooper.mQueue;//获取MessageQuene mCallback = callback; mAsynchronous = async; }
使用
Handler mHandler = new Handler(){ @Override public void handleMessage(@NonNull Message msg) { super.handleMessage(msg); } };
1、拿到mHandler所在线程的Looper,当前mHandler是在Activity中创建的,很明显,当前的线程就是主线程,所以 mHandler的成员变量mLooper = Looper.myLooper(),此处就已经将当前的主线程Looper赋值过去了。
2、紧接着,判断mLooper 是否为空,明显不为空,所以又会将主线程的消息队列赋值给mQueue。告诉Handler,你要是有消息,就送到这个消息队列中来,我(Looper)会一个个按顺序处理,处理完后我就会告诉你,你再处理。
Handler只能绑定一个线程的Looper;
Handler的消息是发送给Looper的消息队列MessageQueue,需要排队处理;
handler的sendMessage方法
public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) { MessageQueue queue = mQueue;//获得当前的消息队列 if (queue == null) { //若是在创建Handler时没有指定Looper,就不会有对应的消息队列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(@NonNull MessageQueue queue, @NonNull Message msg, long uptimeMillis) { msg.target = this; msg.workSourceUid = ThreadLocalWorkSource.getUid(); if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
msg.target = this
在发送消息到消息队列之前,明确的指定了消息的target为当前的Handler,以便于在后面Looper分发消息时用到。
queue.enqueueMessage(msg, uptimeMillis)
然后调用了消息队列的enqueueMessage()方法,并传递了两个参数,一个Message,一个是long型的时间。
Handler dispatchMessage()方法
消息发送后,交给Looper等待处理,处理完后会重新通知Handler处理,那么,是怎样通知Handler处理消息的呢?秘密就在dispatchMessage()这个方法中
public void dispatchMessage(@NonNull Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
当Looper处理完Message后,会使用到Message的target,即上面说到的target,即发送消息的那个Handler,Looper会调用Handler的dispatchMessage()方法分发消息,所以前面在enqueueMessage()发送消息的时候,为什么非得指明Message的target就是这个道理。
回到dispatchMessage()这个方法:
1、首先会判断Message的callback是否为空,此处的callback就是前面我们在Message中说到的,在静态方法创建Message时,可以指定的callback,若不为空,则将结果回调到callback中;
2、若Handler的mCallback 不为空,也一样的道理。
3、平时我们都没有传入这个callback,而是直接实现handleMessage()这个方法,在这个方法中处理更新UI任务。
以上就是Handler发送和接收消息的基本过程:把消息发送到队列—>然后等待—>接收消息—>分发消息—>在回调中处理。
MessageQueue
Handler发送消息会调用MessageQueue的enqueueMessage()方法
boolean enqueueMessage(Message msg, long when) { if (msg.target == null) { //判断msg的所属Handler throw new IllegalArgumentException("Message must have a target."); } synchronized (this) {//因为是队列,有先后之分,所以用了同步机制 if (msg.isInUse()) { throw new IllegalStateException(msg + " This message is already in use."); } if (mQuitting) { IllegalStateException e = new IllegalStateException( msg.target + " sending message to a Handler on a dead thread"); Log.w(TAG, e.getMessage(), e); msg.recycle(); return false; } msg.markInUse(); msg.when = when; Message p = mMessages; boolean needWake; //若队列为空,或者等待时间为0,或者比前面那位的等待时间要短,就插队 if (p == null || when == 0 || when < p.when) { // New head, wake up the event queue if blocked. msg.next = p; mMessages = msg; needWake = mBlocked; } else { // Inserted within the middle of the queue. Usually we don't have to wake // up the event queue unless there is a barrier at the head of the queue // and the message is the earliest asynchronous message in the queue. needWake = mBlocked && p.target == null && msg.isAsynchronous(); Message prev; //此处for循环是为了取出一个空的或者when比当前Message长的一个消息,然后进行插入 for (;;) { prev = p; p = p.next; if (p == null || when < p.when) { break; } if (needWake && p.isAsynchronous()) { needWake = false; } } msg.next = p; // invariant: p == prev.next prev.next = msg; } // We can assume mPtr != 0 because mQuitting is false. if (needWake) { nativeWake(mPtr); } } return true; }
以上就是消息队列插入消息的过程原理,通过单向链表的数据结构来存储消息。既然有了插入消息的方法供Handler插入消息,那么应该有对应的取出消息的方法,供Looper调用取出消息处理,它就是Message.next这个变量(结点)
Looper
Looper在Handler机制中扮演着关键的一环,他是循环处理消息的发动机,永不停息(永动鸡),它不断的从消息队列中取出的消息,处理,然后分发处理事件。每个线程都可以且只能绑定一个Looper。主线程之所以能处理消息,也是因为在APP启动时,在ActivityThread中的main()方法中就已经启动了Looper循环。
public static void loop() { final Looper me = myLooper(); //获得当前的Looper if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } if (me.mInLoop) { Slog.w(TAG, "Loop again would have the queued messages be executed" + " before this one completed."); } me.mInLoop = true; // 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(); // Allow overriding a threshold with a system prop. e.g. // adb shell 'setprop log.looper.1000.main.slow 1 && stop && start' final int thresholdOverride = SystemProperties.getInt("log.looper." + Process.myUid() + "." + Thread.currentThread().getName() + ".slow", 0); me.mSlowDeliveryDetected = false; for (;;) { if (!loopOnce(me, ident, thresholdOverride)) { return; } } }
private static boolean loopOnce(final Looper me, final long ident, final int thresholdOverride) { Message msg = me.mQueue.next(); // might block //取出队头的消息 if (msg == null) { // 如果消息为空,则跳过,继续执行下一个message // No message indicates that the message queue is quitting. return false; } // This must be in a local variable, in case a UI event sets the logger final Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); } // Make sure the observer won't change while processing a transaction. final Observer observer = sObserver; final long traceTag = me.mTraceTag; long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs; long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs; if (thresholdOverride > 0) { slowDispatchThresholdMs = thresholdOverride; slowDeliveryThresholdMs = thresholdOverride; } final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0); final boolean logSlowDispatch = (slowDispatchThresholdMs > 0); final boolean needStartTime = logSlowDelivery || logSlowDispatch; final boolean needEndTime = logSlowDispatch; if (traceTag != 0 && Trace.isTagEnabled(traceTag)) { Trace.traceBegin(traceTag, msg.target.getTraceName(msg)); } final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0; final long dispatchEnd; Object token = null; if (observer != null) { token = observer.messageDispatchStarting(); } long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid); try { msg.target.dispatchMessage(msg); if (observer != null) { observer.messageDispatched(token, msg); } dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0; } catch (Exception exception) { if (observer != null) { observer.dispatchingThrewException(token, msg, exception); } throw exception; } finally { ThreadLocalWorkSource.restore(origWorkSource); if (traceTag != 0) { Trace.traceEnd(traceTag); } } if (logSlowDelivery) { if (me.mSlowDeliveryDetected) { if ((dispatchStart - msg.when) <= 10) { Slog.w(TAG, "Drained"); me.mSlowDeliveryDetected = false; } } else { if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery", msg)) { // Once we write a slow delivery log, suppress until the queue drains. me.mSlowDeliveryDetected = true; } } } if (logSlowDispatch) { showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", 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 true; }
Looper的处理消息的循环还是挺简单的,就是拿出消息,然后分发,然后回收