Handler机制学习

【记录一个问题】

主线程创建一个Handler,在子线程中去调用sendMessage,为什么消息能在主线程中得到处理?

  1. Handler的关联:在主线程中创建的 Handler 自动与主线程的 Looper 关联。
  2. 消息队列的共享sendMessage 方法将消息发送到与 Handler 关联的 Looper 的 MessageQueue 中,这个 MessageQueue 是由 Looper 管理的,而 Looper 是在主线程中运行的。
  3. Looper的循环:主线程中的 Looper 不断地从 MessageQueue 中取出消息并处理它们,直到 Looper 被显式地停止。

目录

Handler流程

1. 异步通信准备

2.消息入队

3.消息循环

 4.消息处理


Handler流程

1. 异步通信准备

在开启应用或者说创建线程的时候就会去创建循环器对象Looper、消息队列MessageQueue;

(以HandlerThread为例)

HandlerThread

  1.    @Override
  2.     public void run() {
  3.         mTid = Process.myTid();
  4.         Looper.prepare();
  5.         synchronized (this) {
  6.             mLooper = Looper.myLooper();
  7.             notifyAll();
  8.         }
  9.         Process.setThreadPriority(mPriority);
  10.         onLooperPrepared();
  11.         Looper.loop();
  12.         mTid = -1;
  13.     }

Looper

  1.     /** Initialize the current thread as a looper.
  2.       * This gives you a chance to create handlers that then reference
  3.       * this looper, before actually starting the loop. Be sure to call
  4.       * {@link #loop()} after calling this method, and end it by calling
  5.       * {@link #quit()}.
  6.       */
  7.     public static void prepare() {
  8.         prepare(true);
  9.     }
  10.     private static void prepare(boolean quitAllowed) {
  11.         if (sThreadLocal.get() != null) {
  12.             throw new RuntimeException("Only one Looper may be created per thread");
  13.         }
  14.         sThreadLocal.set(new Looper(quitAllowed));
  15.     }

ThreadLocal

  1.     /**
  2.      * Returns the value in the current thread's copy of this
  3.      * thread-local variable.  If the variable has no value for the
  4.      * current thread, it is first initialized to the value returned
  5.      * by an invocation of the {@link #initialValue} method.
  6.      *
  7.      * @return the current thread's value of this thread-local
  8.      */
  9.     public T get() {
  10.         Thread t = Thread.currentThread();
  11.         ThreadLocalMap map = getMap(t);
  12.         if (map != null) {
  13.             ThreadLocalMap.Entry e = map.getEntry(this);
  14.             if (e != null) {
  15.                 @SuppressWarnings("unchecked")
  16.                 T result = (T)e.value;
  17.                 return result;
  18.             }
  19.         }
  20.         return setInitialValue();
  21.     }

  1.     /**
  2.      * Sets the current thread's copy of this thread-local variable
  3.      * to the specified value.  Most subclasses will have no need to
  4.      * override this method, relying solely on the {@link #initialValue}
  5.      * method to set the values of thread-locals.
  6.      *
  7.      * @param value the value to be stored in the current thread's copy of
  8.      *        this thread-local.
  9.      */
  10.     public void set(T value) {
  11.         Thread t = Thread.currentThread();
  12.         ThreadLocalMap map = getMap(t);
  13.         if (map != null) {
  14.             map.set(this, value);
  15.         } else {
  16.             createMap(t, value);
  17.         }
  18.     }

【总结】

ThreadLocal是一个创建线程局部变量的类,它的实现机制决定了这个变量的作用域是线程,其他线程访问不了,在Looper中通过prepare函数的设计,确保了一个ThreadLocal 只会和一个Looper进行绑定。通过这两个方式确保了一个线程只有一个ThreadLocal变量,一个ThreadLocal变量只有一个Looper从而形成了一一对应的关系。

当在主线程创建Handler如果不设置Looper的话,就会默认绑定当前线程的Looper;

1.Handler中有成员变量MessageQueue,用于消息存放;

  1.     public Handler(@Nullable Callback callback, boolean async) {
  2.         ......
  3.         mLooper = Looper.myLooper();
  4.         if (mLooper == null) {
  5.             throw new RuntimeException(
  6.                 "Can't create handler inside thread " + Thread.currentThread()
  7.                         + " that has not called Looper.prepare()");
  8.         }
  9.         mQueue = mLooper.mQueue;
  10.         mCallback = callback;
  11.         mAsynchronous = async;
  12.         mIsShared = false;
  13.     }

2.从HandlerThread的run方法可以看出,prepare随后会调用Looper.loop()方法循环去MessagerQueue中去取出消息处理。

  1.     public static void loop() {
  2.         final Looper me = myLooper();
  3.         if (me == null) {
  4.             throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
  5.         }
  6.         ......
  7.         me.mInLoop = true;
  8.         for (;;) {
  9.             if (!loopOnce(me, ident, thresholdOverride)) {
  10.                 return;
  11.             }
  12.         }
  13.     }

2.消息入队

当创建子线程/主线程创建Handler/子线程调用主线程的Handler去sendMessage,就会将该Message发送到与Handler关联的对应Looper初始化所创建的消息队列MessageQueue中。

不论是调用Handler的sendMessage还是sendEmptyMessage方法,最终都是调用sendEmptyMessageDelayed。

  1.     public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
  2.         Message msg = Message.obtain();
  3.         msg.what = what;
  4.         return sendMessageDelayed(msg, delayMillis);
  5.     }

  1.     public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
  2.         if (delayMillis < 0) {
  3.             delayMillis = 0;
  4.         }
  5.         return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
  6.     }

Message obtain方法是从线程池中取出一个Message,sPool(是Message对象)后移一个,将其flag和next置空,线程池为空则创建一个新Message。

  1.     /**
  2.      * Return a new Message instance from the global pool. Allows us to
  3.      * avoid allocating new objects in many cases.
  4.      */
  5.     public static Message obtain() {
  6.         synchronized (sPoolSync) {
  7.             if (sPool != null) {
  8.                 Message m = sPool;
  9.                 sPool = m.next;
  10.                 m.next = null;
  11.                 m.flags = 0// clear in-use flag
  12.                 sPoolSize--;
  13.                 return m;
  14.             }
  15.         }
  16.         return new Message();
  17.     }

最终调用到sendMessageAtTime的目的是传入当前时间+延时时间,以时间为轴将当前Message插入到MessageQueue中,实现有序消息处理。

  1.     public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
  2.         MessageQueue queue = mQueue;
  3.         if (queue == null) {
  4.             RuntimeException e = new RuntimeException(
  5.                     this + " sendMessageAtTime() called with no mQueue");
  6.             Log.w("Looper", e.getMessage(), e);
  7.             return false;
  8.         }
  9.         return enqueueMessage(queue, msg, uptimeMillis);
  10.     }

此处1个关键点

将当前Handler传给Message的target,这个在后面dispatchMessage时候会使用到;

  1.     private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,long uptimeMillis){
  2.         msg.target = this;
  3.         msg.workSourceUid = ThreadLocalWorkSource.getUid();
  4.         if (mAsynchronous) {
  5.             msg.setAsynchronous(true);
  6.         }
  7.         return queue.enqueueMessage(msg, uptimeMillis);
  8.     }

MessageQueue

关键点msg.when就是传入的时间点,通过when,循环找到小when,插入当前Message。

  1.     boolean enqueueMessage(Message msg, long when) {
  2.         if (msg.target == null) {
  3.             throw new IllegalArgumentException("Message must have a target.");
  4.         }
  5.         synchronized (this) {
  6.             if (msg.isInUse()) {
  7.                 throw new IllegalStateException(msg + " This message is already in use.");
  8.             }
  9.             if (mQuitting) {
  10.                 IllegalStateException e = new IllegalStateException(
  11.                         msg.target + " sending message to a Handler on a dead thread");
  12.                 Log.w(TAG, e.getMessage(), e);
  13.                 msg.recycle();
  14.                 return false;
  15.             }
  16.             msg.markInUse();
  17.             msg.when = when;
  18.             Message p = mMessages;
  19.             boolean needWake;
  20.             if (p == null || when == 0 || when < p.when) {
  21.                 // New head, wake up the event queue if blocked.
  22.                 msg.next = p;
  23.                 mMessages = msg;
  24.                 needWake = mBlocked;
  25.             } else {
  26.                 // Inserted within the middle of the queue.  Usually we don't have to wake
  27.                 // up the event queue unless there is a barrier at the head of the queue
  28.                 // and the message is the earliest asynchronous message in the queue.
  29.                 needWake = mBlocked && p.target == null && msg.isAsynchronous();
  30.                 Message prev;
  31.                  for (;;) {
  32.                     prev = p;
  33.                     p = p.next;
  34.                     if (p == null || when < p.when) {
  35.                         break;
  36.                     }
  37.                     if (needWake && p.isAsynchronous()) {
  38.                         needWake = false;
  39.                     }
  40.                 }
  41.                 msg.next = p; // invariant: p == prev.next
  42.                 prev.next = msg; 
  43.             }
  44.             // We can assume mPtr != 0 because mQuitting is false.
  45.             if (needWake) {
  46.                 nativeWake(mPtr);
  47.             }
  48.         }
  49.         return true;
  50.     }

3.消息循环

  1. 前面说到Looper.loop()循环去遍历MeassageQueue,此时当有消息进入就会将该消息取出,然后匹配到创建该消息的Handler中去处理;
  2. 如果MeassageQueue中没有消息,那就阻塞该线程,释放cpu。

LoopOnce主要两个重要作用

  1. 当MessageQueue中没有消息时候,返回false,结束线程
  2. 调用target的dispatchMessage进行消息的分发,target就是所创建的Handler
  1.     private static boolean loopOnce(final Looper me,
  2.             final long ident, final int thresholdOverride) {
  3.         Message msg = me.mQueue.next(); // might block。//code1
  4.         if (msg == null) {
  5.             // No message indicates that the message queue is quitting.
  6.             return false;
  7.         }
  8.         ......
  9.         try {
  10.              msg.target.dispatchMessage(msg);  //code2 
  11.             if (observer != null) {
  12.                 observer.messageDispatched(token, msg);
  13.             }
  14.             dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
  15.         } 
  16.         ......
  17.         msg.recycleUnchecked();
  18.         return true;
  19.     }

code1中当没有消息时,或者消息不满足处理条件,则 nativePollOnce 方法会阻塞线程,直到有满足条件的消息到来。

【MessageQueue.next】

  1.     Message next() {
  2.         .......
  3.         for (;;) {
  4.              ......
  5.             nativePollOnce(ptr, nextPollTimeoutMillis);//code1
  6.         }
  7.     }

【LoopOnce】

上述code2 dispatchMesage需要判断分发Message对象中的callback,如下三种情况:

  1.     public void dispatchMessage(@NonNull Message msg) {
  2.         if (msg.callback != null) {
  3.             handleCallback(msg);//code 1
  4.         } else {
  5.             if (mCallback != null) {
  6.                  if (mCallback.handleMessage(msg)) {//code2 
  7.                     return;
  8.                 }
  9.             }
  10.             handleMessage(msg);//code3
  11.         }
  12.     }

1. code1中是post中的Runnable,执行handleCallback(message.callback.run(););

  1.         mHandler.post(new Runnable() {
  2.             @Override
  3.             public void run() {
  4.                 ......
  5.             }
  6.         });

2. code2中是创建Handler的时候是否传入callback;

  1.         mHandler = new Handler(threadLooper,  new Handler.Callback()  {
  2.             @Override
  3.             public boolean handleMessage(@NonNull Message msg) {
  4.                 if (msg.what == MSG_HELLO) {
  5.                     Log.d(TAG, "handleMessage:  thread id: " + Thread.currentThread().getId());
  6.                 }
  7.                 finish();
  8.                 return true;
  9.             }
  10.         });

3. code3中是执行Handler中的handleMessage,Handler中重写该方法即可。

  1.     private static class MyHandler extends Handler {
  2.         MyHandler(Looper looper) {
  3.             super(looper);
  4.         }
  5.         @Override
  6.         public void handleMessage(@NonNull Message msg) {
  7.             super.handleMessage(msg);
  8.         }
  9.     }

 4.消息处理

     Handler接收到message,在handleMessage中处理UI等相关操作。

  1.      /**
  2.      * Subclasses must implement this to receive messages.
  3.      */
  4.     public void handleMessage(@NonNull Message msg) {
  5.     }
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值