<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                ## 10.1 Android消息機制概述 (1)Android的消息機制主要是指Handler的運行機制,其底層需要`MessageQueue`和`Looper`的支撐。MessageQueue是以單鏈表的數據結構存儲消息列表但是以隊列的形式對外提供插入和刪除消息操作的消息隊列。MessageQueue只是消息的存儲單元,而Looper則是以無限循環的形式去查找是否有新消息,如果有的話就去處理消息,否則就一直等待著。 (2)Handler的主要作用是將一個任務切換到某個指定的線程中去執行。 為什么要提供這個功能呢? Android規定UI操作只能在主線程中進行,`ViewRootImpl`的`checkThread`方法會驗證當前線程是否可以進行UI操作。 為什么不允許子線程訪問UI呢? 這是因為UI組件不是線程安全的,如果在多線程中并發訪問可能會導致UI組件處于不可預期的狀態。另外,如果對UI組件的訪問進行加鎖機制的話又會降低UI訪問的效率,所以還是采用單線程模型來處理UI事件。 (3)Handler的創建會采用當前線程的Looper來構建內部的消息循環系統,如果當前線程中不存在Looper的話就會報錯。Handler可以用`post`方法將一個Runnable投遞到消息隊列中,也可以用`send`方法發送一個消息投遞到消息隊列中,其實`post`最終還是調用了`send`方法。 ## 10.2 Android的消息機制分析 (1)`ThreadLocal`的工作原理 1.ThreadLocal是一個線程內部的數據存儲類,通過它可以在指定的線程中存儲數據,數據存儲以后,只有在指定線程中可以獲取到存儲的數據,對于其他線程來說則無法獲取到數據。一般來說,當某些數據是以線程為作用域并且不同線程具有不同的數據副本的時候,可以考慮使用ThreadLocal。?對于Handler來說,它需要獲取當前線程的Looper,而Looper的作用域就是線程并且不同線程具有不同的Looper,這個時候通過ThreadLocal就可以實現Looper在線程中的存取了。 2.ThreadLocal的原理:不同線程訪問同一個ThreadLocal的`get`方法時,ThreadLocal內部會從各自的線程中取出一個數組,然后再從數組中根據當前ThreadLocal的索引去查找出對應的value值,不同線程中的數組是不同的,這就是為什么通過ThreadLocal可以在不同線程中維護一套數據的副本并且彼此互不干擾。 3.ThreadLocal是一個泛型類`public class ThreadLocal<T>`,下面是它的`set`方法 ~~~ public void set(T value) { Thread currentThread = Thread.currentThread(); Values values = values(currentThread); if (values == null) { values = initializeValues(currentThread); } values.put(this, value); } ~~~ `Values`是Thread類內部專門用來存儲線程的ThreadLocal數據的,它內部有一個數組`private Object[] table`,ThreadLocal的值就存在這個table數組中。如果values的值為null,那么就需要對其進行初始化然后再將ThreadLocal的值進行存儲。 ThreadLocal數據的存儲規則:ThreadLocal的值在table數組中的存儲位置總是ThreadLocal的索引+1的位置。 (2)`MessageQueue`的工作原理 1.MessageQueue其實是通過單鏈表來維護消息列表的,它包含兩個主要操作`enqueueMessage`和`next`,前者是插入消息,后者是取出一條消息并移除。 2.next方法是一個無限循環的方法,如果消息隊列中沒有消息,那么next方法會一直阻塞在這里。當有新消息到來時,next方法會返回這條消息并將它從鏈表中移除。 (3)`Looper`的工作原理 1.為一個線程創建Looper的方法,代碼如下所示 ~~~ new Thread("test"){ @Override public void run() { Looper.prepare();//創建looper Handler handler = new Handler();//可以創建handler了 Looper.loop();//開始looper循環 } }.start(); ~~~ 2.Looper的`prepareMainLooper`方法主要是給主線程也就是`ActivityThread`創建Looper使用的,本質也是調用了`prepare`方法。 3.Looper的`quit`和`quitSafely`方法的區別是:前者會直接退出Looper,后者只是設定一個退出標記,然后把消息隊列中的已有消息處理完畢后才安全地退出。Looper退出之后,通過Handler發送的消息就會失敗,這個時候Handler的send方法會返回false。 在子線程中,如果手動為其創建了Looper,那么在所有的事情完成以后應該調用quit方法來終止消息循環,否則這個子線程就會一直處于等待的狀態,而如果退出Looper以后,這個線程就會立刻終止,因此建議不需要的時候終止Looper。 4.Looper的`loop`方法會調用`MessageQueue`的`next`方法來獲取新消息,而next是一個阻塞操作,當沒有消息時,next方法會一直阻塞著在那里,這也導致了loop方法一直阻塞在那里。如果MessageQueue的next方法返回了新消息,Looper就會處理這條消息:`msg.target.dispatchMessage(msg)`,其中的`msg.target`就是發送這條消息的Handler對象。 (4)Handler的工作原理 1.Handler就是處理消息的發送和接收之后的處理; 2.Handler處理消息的過程 ~~~ public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg);//當message是runnable的情況,也就是Handler的post方法傳遞的參數,這種情況下直接執行runnable的run方法 } else { if (mCallback != null) {//如果創建Handler的時候是給Handler設置了Callback接口的實現,那么此時調用該實現的handleMessage方法 if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg);//如果是派生Handler的子類,就要重寫handleMessage方法,那么此時就是調用子類實現的handleMessage方法 } } private static void handleCallback(Message message) { message.callback.run(); } /** * Subclasses must implement this to receive messages. */ public void handleMessage(Message msg) { } ~~~ 3.Handler還有一個特殊的構造方法,它可以通過特定的Looper來創建Handler。 ~~~ public Handler(Looper looper){ this(looper, null, false); } ~~~ 4.Android的主線程就是`ActivityThread`,主線程的入口方法就是main,其中調用了`Looper.prepareMainLooper()`來創建主線程的Looper以及MessageQueue,并通過`Looper.loop()`方法來開啟主線程的消息循環。主線程內有一個Handler,即`ActivityThread.H`,它定義了一組消息類型,主要包含了四大組件的啟動和停止等過程,例如`LAUNCH_ACTIVITY`等。 `ActivityThread`通過`ApplicationThread`和`AMS`進行進程間通信,AMS以進程間通信的方法完成ActivityThread的請求后會回調ApplicationThread中的`Binder`方法,然后ApplicationThread會向`H`發送消息,`H`收到消息后會將ApplicationThread中的邏輯切換到ActivityThread中去執行,即切換到主線程中去執行,這個過程就是主線程的消息循環模型。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看