簡體   English   中英

Android:從另一個線程向主線程發布runnable實際上做了什么?

[英]Android: What does posting a runnable from another thread onto the main thread actually do?

所以,正如標題所說:當你將另一個線程的runnable發布到主線程上時會發生什么?

我已經看到很多問題,詢問你是如何做到的,以及它的基礎知識是如何工作的。 但是,當你在MessageQueue上放置一個runnable時,我很難找到確切的解釋。 肯定是它在Runnable轉彎時運行。 但這是什么時候?

例如:
假設有一個啟動ASync請求的按鈕,請求返回並觸發在MainThread上運行的runnable / callback。 怎么了? runnable被添加到MessageQueue並在'time'時運行。 但是什么時候到了? 如果我在Async請求發布MainThread上的runnable之前按下另一個在MainThread上執行半長阻塞任務的按鈕怎么辦? 是否等到我的阻止按鈕上的邏輯完成? 它會打斷它嗎? 它是否將可運行代碼與我的阻塞代碼按鈕的代碼交織在一起? 究竟發生了什么?

我問的主要原因是,我可以更好地理解我需要考慮哪些因素來防止多線程引起的錯誤。 (特別是影響已刷新頁面的舊請求的情況)

首先,您需要了解Message類是什么樣的。 Message對象包含以下字段:

    Handler target;     // a handler that enqueued the message
    long when;          // the time at which the message is to be processed 

    [RUNNABLE] Runnable callback;   =
    [SWITCHED] int what, int arg1, int arg2, Bundle data...

    bool isAsynchronous; // I will talk about it in the end

我用[RUNNABLE][SWITCHED]標記的內容表示處理Message的兩種非重疊方式。 如果callback不為null,則忽略所有[SWITCHED]字段。 如果callback為空比Message[SWITCHED]字段和無論是在被處理Handler's被覆蓋的handleMessage()handleMessage()的中Handler.Callback處理程序用初始化。

MessageQueuewhen字段排序。 Looper不會出列消息並處理消息,直到當前時間(由SystemClock.uptimeMillis測量)大於或等於消息的when字段中存儲的時間。

當您調用Handler#post(Runnable r) ,會發生以下情況:

  1. 從池中獲取MessageMessage類中的簡單靜態鏈接列表)

  2. 您的Runnable被分配給消息的callback字段。

  3. when字段被簡單地設置為當前時間,如果沒有延遲或特定時間傳遞

  4. Message被排入MessageQueue 如果when早於隊列頭部的那個,它就變成了一個新頭。 如果不是,則將其插入中間,以便MessageQueuewhen排序

  5. Looper處於非終止循環中,從隊列中出列消息並按順序處理它們(沒有交織),最終使我們的消息出列,並在最初發布Runnable的處理程序上調用dispatchMessage()

  6. 處理程序決定消息是[RUNNABLE]還是[SWITCHED]並相應地處理它。 特別是如果它存在的話,它會在callback上調用run()

這應該回答你關於在阻塞任務期間發布在UI線程上的Runnable的行為的問題 - 好吧, 不,它不會中斷正在進行的任務,也不會交織 線程上發生的所有事情首先進入MessageQueue ,按鈕單擊或您從其他線程發布的自定義Runnables 基本上沒有辦法以其他方式發生: Looper.loop()只是讓線程忙於for(;;)循環。

有一些方法可以改變消息的順序。

例如,Looper / Handler框架中有一個有趣的同步屏障概念。 同步障礙是一種慣例,只是一個帶有空targetMessage (所以它基本上只是一個類似於旗幟的東西,沒有處理程序來調度它)。 如果使用postSyncBarrier()將其放入隊列,則整個隊列的更改將更改,直到使用removeSyncBarrier()從隊列中刪除同步屏障。 未標記為isAsynchronousMessages將被忽略,並且根本不會出列和處理。 而是掃描隊列,直到找到isAsynchronous = true的消息。 然后根據它的時間進行安排,並在時機到來when進行處理。

另外,你可以調用一個不言自明的Handler#postAtFrontOfQueue() ,如文檔中所指出的那樣

此方法僅用於非常特殊的情況 - 它可能很容易使消息隊列餓死,導致排序問題或具有其他意外的副作用。

我建議你瀏覽所有提到的類的源代碼 它讀起來就像一本好書。

MainThread執行了許多其他runnable,例如更新UI,觸摸事件。 '時間'是發布的runnable准備好出列的時間。 如果任何其他runnable出現在它之前,你的runnable將等待。

這里沒有中斷這樣的事情。 你的按鈕將提交一系列runnables,就像從許多不同的線程提交相同數量的runnable一樣。

如果你有一條非短消息(任何包含LONG字對UI不好的話)操作將阻止執行隊列中提交的其他重復任務,大多數情況下經常會證明沒有更新(對於執行不確定的任務)如果是執行需要超過8毫秒的可運行的突發問題,那么根本就是用戶界面。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM