android 消息模型之 執行源碼分析

1.在我看來 一個持續運行應用程序 就是main方法進入 ,然後在裏面使用消息模型不斷接受系統或者用戶的請求並作出對應的處理.例如qt 的信號與槽 ,win32 消息映射(要自己實現) ,android 的handler+looper .他們共同的點一直做死循環,避免程序一運行就退出,  並且不斷接受系統或者用戶的請求並作出對應的處理

2.那麼android應用 最開始是在哪個類進行死循環的呢,答案就在ActivityThread 類中 代碼如下:

 public static void main(String[] args) {
    .....

        Looper.prepareMainLooper(); //創建ui線程的looper 

        ActivityThread thread = new ActivityThread(); 創建 thread 同時也是創建handler H
        thread.attach(false);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        if (false) {
           //如果 mLogging 對象 不爲空,可以在消息處理前後打印日誌 看門狗貌似使用者兩者之間的打印時間差來判斷是否卡頓
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }
// 這裏就是做死循環不斷接受請求和處理請求了.

        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

如果你曾經在 子線程中創建過handler 了 ,那麼這段代碼就非常熟悉了.

3.使用handler 第一步 Looper.prepareMainLooper

 public static void prepareMainLooper() {
        prepare(false);// 這裏會創建 主looper ,並設置不允許退出,退出時會拋異常
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper(); //以當前線程爲key取出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));
    }

   private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed); //創建存儲消息的隊列 這個比較重要 因爲looper像個調度器 基本都是使用message 或者messagequeue 的方法
        mThread = Thread.currentThread();
    }

當然我們一般用的是prepare()方法

3.使用handler 第二步 消息隊列對象MessageQueue創建(核心這個).消息隊列負責對消息的管理和對線程的堵塞與喚醒

    MessageQueue(boolean quitAllowed) {
        mQuitAllowed = quitAllowed;
        mPtr = nativeInit();
    }
nativeInit 是本地方法, 作用就是創建native 層messagequeue 和looper .並在looper 中創建一個文件描述符.使用poll 來實現堵塞 .通過使用write寫東西來poll  不堵塞.對應着nativePollOnce和nativeWake本地方法.具體看源碼

裏面重要的屬性是:mMessages 消息隊列頭(單鏈表來管理的不是隊列) ,mPtr指向native 的隊列對象
重要方法next:
     
      Message next() {
        // Return here if the message loop has already quit and been disposed.
        // This can happen if the application tries to restart a looper after quit
        // which is not supported.
        final long ptr = mPtr;
        if (ptr == 0) {
            return null; //當loop 退出或者銷燬
        }

        int pendingIdleHandlerCount = -1; // -1 only during first iteration
        int nextPollTimeoutMillis = 0;
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands(); //刷新 binder 驅動
            }

            nativePollOnce(ptr, nextPollTimeoutMillis);//處理native層消息或者堵塞用

            synchronized (this) {
                // Try to retrieve the next message.  Return if found.
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                Message msg = mMessages;
              //當鏈表不爲空 handler 爲空 .一般handler 不爲空 那直接跳下一步
                if (msg != null && msg.target == null) {
                    // Stalled by a barrier.  Find the next asynchronous message in the queue.
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    //一般是默認同步 那直接跳下一步
                    } while (msg != null && !msg.isAsynchronous());
                }
                if (msg != null) {
                    if (now < msg.when) {
                        // Next message is not ready.  Set a timeout to wake up when it is ready.
 // 鏈表不爲空 但未到執行時間, 再次循環將堵塞 堵塞時間爲nextPollTimeoutMillis .
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        // Got a message.
//執行時間已到
                        mBlocked = false;
                        if (prevMsg != null) {
                            prevMsg.next = msg.next;//handler 一般不爲空否則毫無意義 跳過
                        } else {
                            mMessages = msg.next; //把下個消息對象賦值給鏈表頭
                        }
                        msg.next = null;//引用置空有利回收
                        if (false) Log.v("MessageQueue", "Returning message: " + msg);
//返回一個消息對象
                        return msg;
                    
                    }
                } else {
                    // No more messages.
                    nextPollTimeoutMillis = -1; //無限循環
                }

                // Process the quit message now that all pending messages have been handled.
                if (mQuitting) {
                    dispose(); //銷燬native 層的隊列
                    return null;
                }

                // If first time idle, then get the number of idlers to run.
                // Idle handles only run if the queue is empty or if the first message
                // in the queue (possibly a barrier) is due to be handled in the future.
                if (pendingIdleHandlerCount < 0
                        && (mMessages == null || now < mMessages.when)) {
// 默認爲空 跳過
                    pendingIdleHandlerCount = mIdleHandlers.size();
                }
                if (pendingIdleHandlerCount <= 0) {
                    // No idle handlers to run.  Loop and wait some more.
                    mBlocked = true; //如果不返回一個消息對象下次循環必然是堵塞 
                    continue;  //默認不執行下面的 所以.....
                }

           .........
    }
重要方法enqueueMessage: 把消息添加到鏈表中
boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {
      //這裏就拋異常了 所以上面不會出現target 爲null 就跳過
            throw new IllegalArgumentException("Message must have a target.");
        }
        if (msg.isInUse()) { //標記是否正在使用
            throw new IllegalStateException(msg + " This message is already in use.");
        }

        synchronized (this) {
            if (mQuitting) {
                IllegalStateException e = new IllegalStateException(
                        msg.target + " sending message to a Handler on a dead thread");
                Log.w("MessageQueue", e.getMessage(), e);
                msg.recycle();
                return false;
            }

            msg.markInUse(); //標記正在使用
            msg.when = when;
            Message p = mMessages;
            boolean needWake;
            if (p == null || when == 0 || when < p.when) {
                // New head, wake up the event queue if blocked.
// 當鏈表爲空,when==0 ,頭消息對象時間大於所要加入消息對象時間 就直接把要添加的消息對象當做頭 
                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 (;;) {
                    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) {
// 喚醒 .假設 你先發送延遲兩秒後執行的p1消息,然後再發送延遲一秒後執行的p2消息
//這時候p2 已經爲頭鏈表對象了 ,我不可能堵塞2秒吧肯定先喚醒再堵塞一秒吧
                nativeWake(mPtr);
            }
        }
        return true;
    }

  



4.第三步 handler 創建: 作用爲將消息添加到消息鏈表中和處理消息

   public Handler(Callback callback, boolean async) {
//靜態屬性,匿名類,內部類..提示內存溢出.
  1.靜態屬性生命週期比activity長 無法回收造成的內存泄漏
  2.匿名類雖然生命週期相同,可是消息隊列(message 持有handler ,handler 持有activity)生命比activity 長 無法回收造成的內存泄漏.所以activity 退出時刪除所有消息.
        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 that has not called Looper.prepare()");
        }

        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

常用方法:sendMessage
      public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);
    }
//最後會調用queue.enqueueMessage 方法加入消息鏈表中(第二步說過略過)
  private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    } 
常用方法:dispatchMessage 處理消息

   public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
//msg 的回調不爲空將執行 msg.callback.run()方法
            handleCallback(msg);
        } else {
            if (mCallback != null) {
 //傳入的回調返回true 將不執行handlMessage
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
//自定義略過
            handleMessage(msg);
        }
    }

5.使用handler第4步 Looper.loop 無限循環:從消息鏈表中獲取message 並回調handler.dispatchMessage(..)方法相對簡單如果看懂上面的話

6.使用handler 第五步 發送消息sendMessage加入消息鏈表後,loop 會在合適的時間取出message 並回調handler.dispatchMessage(..)

ps:有時間畫個圖.不懂看老羅的源代碼情景分析那本書

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章