點擊上方“IT爛筆頭”,選擇“置頂公衆號”
第一時間獲取 IT 技術乾貨!
閱讀文本大概需要 6 分鐘。
1
UI 線 程 的 定 義
作爲一名機智的安卓開發者,似乎每個人心裏都有些公認的約定規則。不在非UI線程中更新UI一定是其中之一,你有沒有想過官方爲什麼不建議我們在非UI線程中去更新UI?在回答這個問題之前,我們先簡單瞭解下何爲UI線程?
UI線程也就是我們平時講的主線程,當系統的zygote進程folk出我們的應用進程時,會爲應用進程創建ActivityThread,這個線程就是我們的主線程,一旦這個線程開啓的時候,其中的Looper就一直死循環的在消息隊列中接收消息用來處理UI相關業務。作爲一個初級工程師這些基本能瞭解。
2
Looper 機 制
這裏我藉助網上的一張圖簡單釋義下這個過程:
圖中畫的過程就是我們的Looper機制,這裏就不再說了,想知道細節的同學可以看我另一篇專門寫Looper的文章:Looper賞析。
當然如果你之前已經看過我的文章了,對Looper機制瞭如指掌,那麼作爲一個中級工程師完全合格了。
3
爲 什 麼 UI 不 是 線 程 安 全 的
官方不讓我們在非UI線程更新UI,原因是UI設計的並非線程安全的,多線程訪問的時候必然會出現展示錯亂,那麼有人就會問了,那將UI設計成線程安全的不就行了嗎?
OK,那麼我們就假設將UI設計成線程安全的,那麼當有很多線程去更新UI的時候,必然會涉及到上鎖和釋放鎖,這個過程吃開銷。而UI的更新頻率是非常高的,顯然不適合頻繁的上鎖和釋放鎖,所以官方將UI設計成只在一個線程去更新,也不需要線程安全。
小結一下爲什麼UI不設計成線程安全的?
UI是頻繁的變更的
UI需要高效的響應操作,不能頻繁加鎖
UI組件需要批量同時繪製保證高效
綜上,UI就不宜設計成線程安全的。
那麼有人講了,那不對啊,我怎麼記得可以在子線程更新UI呢?你看我是這麼寫的:
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fake);
fakeText = findViewById(R.id.fake_tips);
fakeText.setText("主線程");
new Thread(new Runnable() {
@Override
public void run() {
fakeText.setText("子線程");
fakeText.setTextColor(Color.BLACK);
}
}).start();
}
然後就能正常看到text變成“子線程”了,也沒有報錯啊。
然後,我們將代碼稍作修改:
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fake);
fakeText = findViewById(R.id.fake_tips);
fakeText.setText("主線程");
new Thread(new Runnable() {
@Override
public void run() {
try {
// 線程等待500毫秒
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
fakeText.setText("子線程");
fakeText.setTextColor(Color.BLACK);
}
}).start();
}
我們讓子線程沉睡了500毫秒以後再更新UI,這時候就報錯了。如果你看過源碼,其實你應該知道,只要你足夠快,在主線程創建頁面根佈局之前去修改UI,就不會報錯。其實這麼做也沒有實際意義,只是從咬文嚼字上說我們確實可以在子線程修改了UI。
其實還有一個在子線程中更新UI的場景,實際使用的特別多。那就是SurfaceView,像我們的視頻(VideoView)以及很多遊戲都是使用SurfaceView來處理的,因爲這些場景需要非常高的頻率刷新UI,不太適合放到我們主線程的UI一起操作,所以他們就被設計成在自己單獨的線程處理。
我們將這個簡單化的講一下,更直白一點就是主線程裏面的UI都在同一個window裏面,SurfaceView相當於在這個window裏面挖了個洞,SurfaceView就是顯示在洞的後面也就是window的後面,你可以在洞的上方放一些View,這樣看起來就是SurfaceView上面疊加了一些普通的View。
推薦閱讀:
THANDKS
- End -