Android Handlerソースコードの正しい姿勢をアーキテクチャの観点から分析する


Handlerの原理は何ですか?Handlerの実現メカニズムを深く分析できますか?面接官は、handlerのソースコード、handlerメカニズムがどのように実現されているのか、メッセージポンプLooperについて理解していない(より完全なプロジェクトがダウンロードされています.未完は続きます.ソースコード.図文の知識はgithubにアップロードされます).
1.Handlerメカニズムの概要
  • Androidメッセージングメカニズムの定義
  • 作用
  • マルチスレッドのアプリケーションシーンでは、作業スレッドでUIを更新する必要がある操作情報をUIマスタースレッドに伝達し、作業スレッドによるUIの更新処理を実現し、最終的に非同期メッセージの処理を実現する
    Handlerを使用する理由:作業スレッドがUIを操作する必要があるというメッセージをメインスレッドに伝え、メインスレッドが作業スレッドの必要に応じてUIを更新できるようにし、スレッドの操作が安全でないという問題を回避する
    2.知識の準備Handlerメカニズムのソースコード分析を読む前に、Handlerのいくつかの備蓄知識を理解してください:関連概念、使用方法&動作原理######2.1関連概念Handlerメカニズムに関する概念は以下の通りである.
    以下の説明の中で、私は直接英文名を使って説明して、すなわちHandlerMessageMessage QueueLooperHandlerを使って、みんなが先に関連概念を熟知することを望みます
    2.2使用方法
  • Handler.sendMessage()使用方法は、メッセージキューにメッセージを送信する方法によって異なり、使用 Handler.post()Handler
  • 次のソース分析は使用手順に従って説明する
  • 3.Handlerメカニズムのコアクラス
    ソースコード分析の前に、Handlerメカニズムのコアクラスを理解します.
    3.1類説明(Handler)メカニズムには3つの重要なクラスがあります.
  • プロセッサクラス(MessageQueue)
  • メッセージキュークラス(Looper)
  • 循環器類Handler3.2 Handlerワークフロー
  • 4.ソース分析
  • 以下のソースコード解析はHandlerの使用手順に従って
  • Handler.sendMessage()使用方法はメッセージキューにメッセージを送信する方法によって異なり、使用Handler.post()、使用ActivityThread
  • の2種類に分けられる.
  • 以下のソースコード解析は、上記2つの使用方法に従って
  • 方式1:Handlerを用いる.sendMessage()
    手順の使用
    /** 
      *                  
      */
      //   1:                Handler   
      private Handler mhandler = new  Handler(){
                    //     handlerMessage()      UI   
                    @Override
                    public void handleMessage(Message msg) {
                            ...//     UI  
                        }
                };
    
      //   2:      
        Message msg = Message.obtain(); //        
        msg.what = 1; //     
        msg.obj = "AA"; //       
    
      //   3:         Handler          
      //       AsyncTask、  Thread 、  Runnable
       mHandler.sendMessage(msg);
    
      //   4:      (     Handler)
      //       AsyncTask、  Thread 、  Runnable
  • ソース分析以下、上記各ステップに従ってソース分析
  • 手順1:メインスレッドで匿名の内部クラスからHandlerクラスオブジェクトを作成する
    /** 
      *     
      */
        private Handler mhandler = new  Handler(){
            //     handlerMessage()      UI   
            @Override
            public void handleMessage(Message msg) {
                    ...//     UI  
                }
        };
    
    /** 
      *     :Handler     
      *   :   Handler   &     
      *  :
      *   a. Handler          ;   ,Handler               
      *   b.      =    Looper  ,      Looper        (  Looper           )
      *   c.  :   Handler    Looper   =     Looper       
      */
      public Handler() {
    
                this(null, false);
                // ->>  1
    
        }
    /** 
      *   1:this(null, false) = Handler(null,false)
      */
      public Handler(Callback callback, boolean async) {
    
                ...//        
    
                // 1.   Looper  
                    mLooper = Looper.myLooper();
                    if (mLooper == null) {
                        throw new RuntimeException(
                            "Can't create handler inside thread that has not called Looper.prepare()");
                    }
                    // Looper.myLooper()  :       Looper  ;    Looper       
                    //   :       Looper  ,      Handler  
                    //            Handler  ,     Looper  
                    //  :   Loop.getMainLooper()             Looper  
    
                // 2.         (MessageQueue)
                    mQueue = mLooper.mQueue;
                    //    Looper            (MessageQueue)
                    //   ,   handler       Looper   MessageQueue
        }
  • 以上から分かるように、Handlerオブジェクトを作成すると、構築方法によって現在のスレッドのLooperオブジェクト&対応するメッセージキューオブジェクト(MessageQueue)が自動的に関連付けられ、Handlerオブジェクトの作成操作を実現するスレッド0が自動的にバインドされるようになると、現在のスレッドのLooperオブジェクト&対応するメッセージキューオブジェクト(MessageQueue)はいつ作成されますか?
    上記の使用手順では、Looperオブジェクト&対応するメッセージキューオブジェクト(MessageQueue)を作成する手順はありません.

  • 手順1までの暗黙的な操作1:ループオブジェクト(Looper)&メッセージキューオブジェクト(MessageQueue)の作成
  • ソースコード分析
  • /** 
      *     1:Looper.prepare()
      *   :     (   )   1      (Looper),      1       (MessageQueue)
      *  :             
      */
        public static final void prepare() {
    
            if (sThreadLocal.get() != null) {
                throw new RuntimeException("Only one Looper may be created per thread");
            }
            // 1.   sThreadLocal   null,      
            //  Looper.prepare()          = 1        1 Looper  
            //  :sThreadLocal = 1 ThreadLocal  ,         
    
            sThreadLocal.set(new Looper(true));
            // 2.     Looper.prepare(),   Looper   &    ThreadLocal   
            //  :Looper      Thread    
            //     Looper     ->>  a
        }
    
      /** 
        *   a:Looper     
        **/
    
            private Looper(boolean quitAllowed) {
    
                mQueue = new MessageQueue(quitAllowed);
                // 1.   1       (MessageQueue)
                //      1 Looper   ,                  (MessageQueue)
    
                mRun = true;
                mThread = Thread.currentThread();
            }
    
    /** 
      *     2:Looper.prepareMainLooper()
      *   :     (UI  )   1      (Looper),      1       (MessageQueue)
      *  :       (UI  )       ,      Looper      ,      
      */
        //  Android       ,     1    (ActivityThread,  UI  )
        //    ,     ActivityThread 1    main()   =        
        // main()     Looper.prepareMainLooper()      1 Looper  
    
          /** 
            *     :main()
            **/
            public static void main(String[] args) {
                ... //        
    
                Looper.prepareMainLooper(); 
                // 1.       1 Looper  ,    1       (MessageQueue)
                //       Looper.prepare()
                //  :prepare():       1 Looper  
    
                ActivityThread thread = new ActivityThread(); 
                // 2.      
    
                Looper.loop(); 
                // 3.           ->>       
    
            }

    まとめ:
  • メインスレッドを作成すると、main()の静的main()が自動的に呼び出されます.一方、Looper.prepareMainLooper()内ではLooperメインスレッドを呼び出して1つのMessageQueueオブジェクトを生成するとともに、対応するLooperオブジェクトも生成する
    1.すなわち、メインスレッドのLooper.prepare()オブジェクトは自動的に生成され、手動で生成する必要はない.一方、サブスレッドのLooperオブジェクトは、Looperで手動で作成する必要がある.サブスレッドでLooperオブジェクトを手動で作成しないとHandlerオブジェクトは生成されません
  • Handlerの役割に従って(メインスレッドでUIを更新する)、したがってHandlerインスタンスの作成シーンは主にメインスレッド
  • 生成MessageQueue&Looper.loop()オブジェクトは、自動的にメッセージループに入ります. は、別の暗黙的な操作です.ステップ1の前の暗黙的な操作2:メッセージループここでは主にLooperクラスにおけるloop()メソッド
  • /**

    • : Looper.loop()
    • : , 、 Handler
    • a. ,
    • b. : MessageQueue quit()
      */
      public static void loop() {

      ...//        
      
      // 1.     Looper     
          final Looper me = myLooper();
          if (me == null) {
              throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
          }
          // myLooper()  :  sThreadLocal   Looper  ; me null      
          //  loop()       prepare(),    1 Looper  
      
          final MessageQueue queue = me.mQueue;
          //   Looper          (MessageQueue)
      
      // 2.     (  for  )
          for (;;) {
      
          // 2.1           
          Message msg = queue.next(); 
          if (msg == null) {
              return;
          }
          // next():          
          //         ,     
          // ->>   1 
      
          // 2.2         Handler
          msg.target.dispatchMessage(msg);
          //    Message       msg target  
          // target     1 handler  
          // ->>  2
      
      // 3.          
      msg.recycle();
      }

      }

    /**

    • 1:queue.next()
    • : (MessageQueue)
    • : ,
      */
      Message next() {

      ...//        
      
      //                   
      //                   or     
      int nextPollTimeoutMillis = 0;
      
      for (;;) {
          if (nextPollTimeoutMillis != 0) {
              Binder.flushPendingCommands();
          }
      
      // nativePollOnce   native ,  nextPollTimeoutMillis -1,             
      nativePollOnce(ptr, nextPollTimeoutMillis);
      
      synchronized (this) {
      
          final long now = SystemClock.uptimeMillis();
          Message prevMsg = null;
          Message msg = mMessages;
      
          //     ,            :   Message       
          if (msg != null) {
              if (now < msg.when) {
                  nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
              } else {
                  //      
                  mBlocked = false;
                  if (prevMsg != null) {
                      prevMsg.next = msg.next;
                  } else {
                      mMessages = msg.next;
                  }
                  msg.next = null;
                  if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                  msg.markInUse();
                  return msg;
              }
          } else {
      
              //            ,  nextPollTimeoutMillis    -1
              //      ,           
              nextPollTimeoutMillis = -1;
          }
      
          ......
      }
         .....

      }
      }//

    /**

    • 2:dispatchMessage(msg)
    • : (Handler)
    • : Handler & msg
      */
      public void dispatchMessage(Message msg) {

      // 1. msg.callback , post(Runnable r)
      // handleCallback(msg), Runnable run()
      // “post(Runnable r)”
      if (msg.callback != null) {
      handleCallback(msg);
      } else {
      if (mCallback != null) {
      if (mCallback.handleMessage(msg)) {
      return;
      }
      }

          // 2.  msg.callback    ,      sendMessage(Message msg)    (       )
          //    handleMessage(msg),      handleMessage(msg) ->>   3
          handleMessage(msg);
      
      }

      }

      /**

      • 3:handleMessage(msg)
      • : = , Handler =
        **/
        public void handleMessage(Message msg) {
        ... // Handler
        }

        
        ###   :
    • = + Handler

    • Handler : dispatchMessage(msg)handleMessage(Message msg)を して し、 には き みのmsg.callbackをコールバックしてメッセージ の

    • を する
    • に :メッセージ
    • (dispatchMessage(msg))

      、1 の の が われます.post(Runnable r) が でなければ、Runnableを してメッセージを したことを し、 コールバックrun() に されたmsg.callback が であれば、sendMessage(Message msg)を してメッセージを したことを す.
      2:メッセージ・オブジェクトの
      /** 
        *     
        */
          Message msg = Message.obtain(); //        
          msg.what = 1; //     
          msg.obj = "AA"; //       
      
      /** 
        *     :Message.obtain()
        *   :      
        *  :  Message       new   Message.obtain()
        */
        public static Message obtain() {
      
              // Message     1 Message ,  Message       
              //   obtain()         
              synchronized (sPoolSync) {
                  if (sPool != null) {
                      Message m = sPool;
                      sPool = m.next;
                      m.next = null;
                      m.flags = 0; // clear in-use flag
                      sPoolSize--;
                      return m;
                  }
                  //   :  obtain()”  “    ,       new      
              }
              //            ,       new  
              return new Message();
      
          }
          ###   3:                 

      マルチスレッドの :handleMessage(msg), Threadクラス, AsyncTask
      /** 
        *     
        */
      
          mHandler.sendMessage(msg);
      
      /** 
        *     :mHandler.sendMessage(msg)
        *   :      (Handler)   
        *   :             (Message ->> MessageQueue)
        */
        public final boolean sendMessage(Message msg)
          {
              return sendMessageDelayed(msg, 0);
              // ->>  1
          }
      
               /** 
                 *   1:sendMessageDelayed(msg, 0)
                 **/
                 public final boolean sendMessageDelayed(Message msg, long delayMillis)
                  {
                      if (delayMillis < 0) {
                          delayMillis = 0;
                      }
      
                      return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
                      // ->>   2
                  }
      
               /** 
                 *   2:sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis)
                 **/
                 public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
                          // 1.            (MessageQueue)
                          MessageQueue queue = mQueue;
      
                          // 2.    enqueueMessage   ->>  3
                          return enqueueMessage(queue, msg, uptimeMillis);
                      }
      
               /** 
                 *   3:enqueueMessage(queue, msg, uptimeMillis)
                 **/
                  private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
                       // 1.  msg.target   this
                       //   :     Handler      msg target  
                       msg.target = this;
                       //         Looper loop()      ,             msg,    msg.target.dispatchMessage(msg)     
                       //                Handler          
      
                      // 2.        enqueueMessage()
                      //  :Handler     ,          ->>  4
                      return queue.enqueueMessage(msg, uptimeMillis);
              }
      
              /** 
                *   4:queue.enqueueMessage(msg, uptimeMillis)
                *   :       (MessageQueue)   
                *   :  ,                   (Message ->> MessageQueue)
                *        :      、       
                */
                boolean enqueueMessage(Message msg, long when) {
      
                      ...//        
      
                      synchronized (this) {
      
                          msg.markInUse();
                          msg.when = when;
                          Message p = mMessages;
                          boolean needWake;
      
                          //            
                              // a.   ,               &              ,   
                              if (p == null || when == 0 || when < p.when) {
                                  msg.next = p;
                                  mMessages = msg;
                                  needWake = mBlocked;
                              } else {
                                  needWake = mBlocked && p.target == null && msg.isAsynchronous();
                                  Message prev;
      
                              // b.           ,      (Message)            
                                  for (;;) {
                                      prev = p;
                                      p = p.next;
                                      if (p == null || when < p.when) {
                                          break;
                                      }
                                      if (needWake && p.isAsynchronous()) {
                                          needWake = false;
                                      }
                                  }
      
                                  msg.next = p; 
                                  prev.next = msg;
                              }
      
                              if (needWake) {
                                  nativeWake(mPtr);
                              }
                          }
                          return true;
                  }
      
      //   ,  Looper         
      //           Handler      &      Handler
      //     Handler.handleMessage()    
      

      (より くの なプロジェクトがダウンロードされています. は きます.ソースコード. の はgithubをアップロードします.)Runnable