美文网首页Android 源码分析
Android 源码(6) --- 异步消息机制Handler、

Android 源码(6) --- 异步消息机制Handler、

作者: jfson_土豆 | 来源:发表于2017-05-20 13:19 被阅读24次

    Handler、Looper、MessageQueue 初始化

    • 1.在 UI 线程创建 Handler,通常直接new Handler;
    private Handler mHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                }
            }
    
    UI Thread 初始Handler化时 对Looper进行初始化过程, main()是在 UI Thread 启动时调用
    
    ```
     public static void main(String[] args) {
            SamplingProfilerIntegration.start();
            
            CloseGuard.setEnabled(false);
    
            Environment.initForCurrentUser();
    
            EventLogger.setReporter(new EventLoggingReporter());
    
            Security.addProvider(new AndroidKeyStoreProvider());
    
            final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
            TrustedCertificateStore.setDefaultUserDirectory(configDir);
    
            Process.setArgV0("<pre-initialized>");
    
            Looper.prepareMainLooper();
    
            ActivityThread thread = new ActivityThread();
            thread.attach(false);
    
            if (sMainThreadHandler == null) {
                sMainThreadHandler = thread.getHandler();
            }
    
            if (false) {
                Looper.myLooper().setMessageLogging(new
                        LogPrinter(Log.DEBUG, "ActivityThread"));
            }
    
            Looper.loop();
    
            throw new RuntimeException("Main thread loop unexpectedly exited");
        }
    ```
    查看一下代码,主要关注一下:Looper.prepareMainLooper();
    
    ```
    public static void prepareMainLooper() {
            prepare(false);
            synchronized (Looper.class) {
                if (sMainLooper != null) {
                    throw new IllegalStateException("The main Looper has already been prepared.");
                }
                sMainLooper = myLooper();
            }
        }
        
    public static void prepare() {
            prepare(f);
        }
        
    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));
    _    }
    ```
    以上是UI Thread 初始化new Handler 调用过程
    
    • 2.接下来看一下 Other Thread 初始化调用。

      Looper.prepare();
      private Handler mHandler = new Handler() {
              @Override
              public void handleMessage(Message msg) {
                  super.handleMessage(msg);
                  }
              }
      

      查看下Looper.prepare();

      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));
      _    }
      
      
    • 3.其他用法: 在其他地方需要用到Handler,并且需要刷新UI时,不通过Looper.prepare();调用,通过Looper.getMainLooper()也可以;
    ` Handler mHandler = new Handler(Looper.getMainLooper());
    
    class Looper{
        public static Looper getMainLooper() {
            synchronized (Looper.class) {
                return sMainLooper;
            }
        }
    } `
    
    • 4.MessageQueue 初始化

       private Looper(boolean quitAllowed) {
              mQueue = new MessageQueue(quitAllowed);
              mThread = Thread.currentThread();
          }
          ```
      Looper 在初始化时创建一个关联MessageQueue,一个线程中对应一个Looper & MessageQueue 
          
      
    • Handler 初始化

      // 常用构造
      public Handler(Callback callback) {
          this(callback, false);
      }
      
       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 初始化时,关联了线程唯一的Looper & MessageQueue。
      
      
      
    • UI Thread 和 其他 Thread 初始完Looper和MessageQueue后,会调用Looper.loop(),来轮询分发消息。

    • 5.梳理一下调用关系,来张流程图理解一下;

      • UI Thread:
        ActivityThread.main() -->Looper.prepareMainLooper() --> prepare(false) --> new Looper(quitAllowed) --> new MessageQueue(quitAllowed)

      • Other Thread:
        prepare() --> prepare(true) --> new Looper(quitAllowed) --> new MessageQueue(quitAllowed)

    Handler-Looper-MessageQueue流程图Handler-Looper-MessageQueue流程图

    异步消息

    • 1.调用,存储消息
      mHandler.sendMessage(new Message()); mHandler.post(); mHandler.postDelay();

      追踪一下不难发现,最后都走的一个地方

        private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
                msg.target = this;
                if (mAsynchronous) {
                    msg.setAsynchronous(true);
                }
                return queue.enqueueMessage(msg, uptimeMillis);
            }
            
    
    这样看msg.target = this;msg.target就是Handler自己,而MessageQueue就是Looper中关联的对象,而enqueueMessage()中是对message保存,进行Message.next()按时间排序。
    
    • 2.消费
      Looper.loop()是对MessageQueue的消费
         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.recycleUnchecked();
            }
        }
       
    

    看到loop()中,添加了一个死循环,不断去轮训MessageQueue中的队列是否为null,返回或者取出来继续执行 msg.target.dispatchMessage(msg);在最开始我们看到msg.target就是Handler本身

        public static Handler mHandler = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    if (msg.what == 101) {
                        Log.i(TAG, "接收到handler消息...");
                    }
                }
            };
            
    

    而handleMessage就是我们重写的回调方法。

    • 3.一张图梳理一下流程


      流程图流程图

    相关文章

      网友评论

        本文标题:Android 源码(6) --- 异步消息机制Handler、

        本文链接:https://www.haomeiwen.com/subject/sdcpxxtx.html