為何invalidate()不可以直接在UI線程中調用
1、android ui操作為什麽一定要在主線程中執行?
答:Android UI操作是單線程模型,關於UI更新的相關API(包括invalidate())都是按照單線程設計的,對於多線程運行時不安全的,即在非主線程調invalidate()刷新界面出現異常。所以android禁止在非主線程更新UI。
2、為什麽說invalidate()是線程不安全的?
答:在非UI線程中調用invalidate會導致線程不安全,也就是說可能在非UI線程中刷新界面的時候,UI線程(或者其他非UI線程)也在刷新界面,這樣就導致多個界面刷新的操作不能同步,導致線程不安全。
3、為何invalidate()不可以直接在UI線程中調用?
答:Android主線程的執行,是通過Looper循環調度消息的機制運行的;主線程一直在執行Looper循環中,更新UI需要通過Handler往消息隊列發送消息,Looper調度到以後便可以執行invalidate()。
android中實現view的更新有兩組方法,一組是invalidate,另一組是postInvalidate,其中前者是在UI線程自身中使用,而後者在非UI線程中使用。
Android提供了Invalidate方法實現界面刷新,但是Invalidate不能直接在線程中調用,因為他違背了Android UI操作的單線程模型。
invalidate方式刷新界面需要借助handler發送消息給UI線程,排隊輪到時,收到刷新指令,才調用invalidate()開始刷新
postInvalidate方式底層的實現,是和上述invalidate方式一樣的,借助於handler發送消息。源碼參考https://blog.csdn.net/ziwang_/article/details/65690751
// 在onCreate()中開啟線程 new Thread(new GameThread()).start();、 // 實例化一個handler Handler myHandler = new Handler() { // 接收到消息後處理 public void handleMessage(Message msg) { switch (msg.what) { case Activity01.REFRESH: mGameView.invalidate(); // 刷新界面 break; } super.handleMessage(msg); } }; class GameThread implementsRunnable { public void run() { while (!Thread.currentThread().isInterrupted()) { Message message = new Message(); message.what = Activity01.REFRESH; // 發送消息 Activity01.this.myHandler.sendMessage(message); try { Thread.sleep(100); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } }
class GameThread implements Runnable { public void run() { while (!Thread.currentThread().isInterrupted()) { try { Thread.sleep(100); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } // 使用postInvalidate可以直接在線程中更新界面 mGameView.postInvalidate(); } } }
為何invalidate()不可以直接在UI線程中調用