<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Handle的原理(Looper、Handler、Message三者關系)

      轉載請注明出處:http://blog.csdn.net/lowprofile_coding/article/details/72580044

      介紹

      前面的內容對Handler做了介紹,也講解了如何使用handler,但是我們并不知道他的實現原理。本文從源碼的角度來分析如何實現的。

      首先我們得知道Handler,Looper,Message Queue三者之間的關系

      • Handler封裝了消息的發送,也負責接收消。內部會跟Looper關聯。
      • Looper 消息封裝的載,內部包含了MessageQueue,負責從MessageQueue取出消息,然后交給Handler處理
      • MessageQueue 就是一個消息隊列,負責存儲消息,有消息過來就存儲起來,Looper會循環的從MessageQueue讀取消息。

      源碼分析

      當我們new一個Handler對象的時候,看看他的構造方法里面做了什么.

      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;
      }
      

      從源碼中我們看到他會調用Looper.myLooper方法獲取一個Looper對象,然后從Looper對象獲取到MessageQueue對象。

      Looper myLooper()

      跟進去看看Looper.myLooper()方法做了什么。這是一個靜態方法,可以類名.方法名直接調用。

      public static @Nullable Looper myLooper() {
          return sThreadLocal.get();
      }
      

      這個方法里面就一行代碼,從sThreadLocal中獲取一個Looper對象,sThreadLocal是一個ThreadLocal對象,可以在一個線程中存儲變量。底層是ThreadLocalMap,既然是Map類型那肯定得先set一個Looper對象,然后我們才能從sThreadLocal對象里面get一個Looper對象。

      ActivityThread main()

      說到這里得給大家介紹一個新的類ActivityThread,ActivityThread類是Android APP進程的初始類,它的main函數是這個APP進程的入口。我們看看這個main函數干了什么事情。

      public static final void main(String[] args) {
              ------
              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();
              -----
      }
      

      在第二行代碼調用Looper.prepareMainLooper()方法,第13行調用了Looper.loop()方法。

      Looper prepareMainLooper()

      繼續跟進Looper.prepareMainLooper()方法,在這個方法中第一行代碼調用了內部的prepare方法。prepareMainLooper有點像單例模式中的getInstance方法,只不過getInstance會當時返回一個對象,而prepareMainLooper會新建一個Looper對象,存儲在sThreadLocal中。

      public static void prepareMainLooper() {
          prepare(false);
          synchronized (Looper.class) {
              if (sMainLooper != null) {
                  throw new IllegalStateException("The main Looper has already been prepared.");
              }
              sMainLooper = myLooper();
          }
      }
      

      Looper prepare()

      繼續跟進prepare方法,看第5行代碼,新建了一個Looper對象,調用sThreadLocal.set方法把Looper對象保存起來。看到這里我想聰明的你們肯定明白了為什么new Handler對象的時候調用Looper.myLooper()方法能從sThreadLocal對象中取到Looper對象。

      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));
      }
      

      Looper 構造方法

      文章開頭我們就講到Looper內部包含了MessageQueue,其實就是在new Looper對象的時候就new了一個MessageQueue對象。

      private Looper(boolean quitAllowed) {
          mQueue = new MessageQueue(quitAllowed);
          mThread = Thread.currentThread();
      }
      

      Looper loop()

      ActivityThread類main方法中調用了Looper的兩個方法,前面我們解釋了prepareMainLooper(),現在來看第二個方法loop()。

      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.");
          }
          final MessageQueue queue = me.mQueue;//從Looper對象獲取MessageQueue對象
      
          // 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 (;;) {//死循環  一直從MessageQueue中遍歷消息
              Message msg = queue.next(); // might block
              if (msg == null) {
                  return;
              }
      
              // 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);
              }
      
              final long traceTag = me.mTraceTag;
              if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
                  Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
              }
              try {
                  //調用handler的dispatchMessage方法,把消息交給handler處理
                  msg.target.dispatchMessage(msg);
              } finally {
                  if (traceTag != 0) {
                      Trace.traceEnd(traceTag);
                  }
              }
      
              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();
          }
      }
      

      這個方法的代碼呢比較多。我都給代碼加上了注釋。其實就是一個死循環,一直會從MessageQueue中取消息,如果取到了消息呢,會執行msg.target.dispatchMessage(msg)這行代碼,msg.target就是handler,其實就是調用handler的dispatchMessage方法,然后把從MessageQueue中取到的message傳入進去。

      Handler dispatchMessage()

      public void dispatchMessage(Message msg) {
          //如果callback不為空,說明發送消息的時候是post一個Runnable對象
          if (msg.callback != null) {
              handleCallback(msg);
          } else {
              if (mCallback != null) {//這個是用來攔截消息的
                  if (mCallback.handleMessage(msg)) {
                      return;
                  }
              }
              handleMessage(msg);//最終調用我們重寫的handleMessage方法
          }
      }
      

      這個方法對消息做最后處理,如果是post類型調用handleCallback方法處理,如果是sendMessage發送的消息。看我們有沒有攔截消息,如果沒有最終調用handleMessage方法處理。

      Handler handleCallback()

      看到這里我們知道為什么post一個Runnable對象,run方法執行的代碼在主線程了吧,因為底層根本就沒有開啟線程,就只是調用了run方法而已。

      private static void handleCallback(Message message) {
          message.callback.run();
      }
      

      前面我們從創建handler對象開始,以及創建Looper,創建MessageQueue的整個流程,現在來分析下,當我們調用post以及sendMessage方法時,怎么把Message添加到MessageQueue。

      Handler post()

      調用了getPostMessage方法,把Runnable傳遞進去。

      public final boolean post(Runnable r)
      {
         return  sendMessageDelayed(getPostMessage(r), 0);
      }
      

      Handler getPostMessage()

      首先調用Message.obtain()方法,取出一個Message對象,這個方法之前有講過,然后把Runnable對象賦值了Message對象的callback屬性。看到這里我們也明白了dispatchMessage方法為什么要先判斷callback是否為空了吧。

      private static Message getPostMessage(Runnable r) {
          Message m = Message.obtain();
          m.callback = r;
          return m;
      }
      

      Handler enqueueMessage()

      在post方法里面調用了sendMessageDelayed方法,其實最終調用的是enqueueMessage方法,所以我這里就直接看enqueueMessage方法源碼。第一行代碼就把handler自己賦值給messgae對象的target屬性。然后調用MessageQueue的enqueueMessage方法把當前的Messgae添加進去。

      private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
          msg.target = this;
          if (mAsynchronous) {
              msg.setAsynchronous(true);
          }
          return queue.enqueueMessage(msg, uptimeMillis);
      }
      

      總結

      總結:handler負責發送消息,Looper負責接收Handler發送的消息,并直接把消息回傳給Handler自己。MessageQueue就是一個存儲消息的容器。

      如果你想第一時間看我的后期文章,掃碼關注公眾號,每周不定期推送Android開發實戰教程文章...

            Android開發666 - 安卓開發技術分享
                   掃描二維碼加關注
      

      Android開發666

      posted @ 2017-05-20 16:16  安輝  閱讀(12708)  評論(1)    收藏  舉報
      主站蜘蛛池模板: 97人洗澡人人澡人人爽人人模| 香蕉EEWW99国产精选免费| 国产在线视频导航| 望江县| 精品一卡2卡三卡4卡乱码精品视频| 国产日韩乱码精品一区二区| 婷婷综合久久中文字幕| 看黄a大片日本真人视频直播| 欧美做受视频播放| 国外av片免费看一区二区三区| 亚洲色婷婷综合开心网| 国产精品福利自产拍在线观看| 国产女人喷潮视频免费| 国产360激情盗摄全集| 狠狠爱五月丁香亚洲综| 性高湖久久久久久久久| 国精品午夜福利不卡视频| 国产一区二区三区精美视频| 潮喷失禁大喷水无码| 99re6在线视频精品免费下载| 国产精品亚洲精品日韩已满十八小| 97国产揄拍国产精品人妻| 老司机精品成人无码AV| 99国内精品久久久久久久| 国产成人精品1024免费下载| 日韩午夜午码高清福利片| 久草网视频在线观看| 亚洲综合色丁香婷婷六月图片| 自拍第一区视频在线观看| 亚洲精品一二三在线观看| 92国产福利午夜757小视频| 乱熟女高潮一区二区在线| 日本不卡的一区二区三区| 亚洲精品一区二区美女| 欧美人与zoxxxx另类| 亚洲熟女国产熟女二区三区| 亚洲真人无码永久在线| 亚洲精品国产中文字幕| 国产亚洲精品VA片在线播放 | 精品国产高清中文字幕| 果冻传媒色av国产在线播放 |