invalidate postinvalidate postinvalidateonanimation三者的區別

invalidate()是用來刷新View的,必須是在UI線程中進行工作。比如在修改某個view的顯示時,調用invalidate()才能看到重新繪制的界面。invalidate()的調用是把之前的舊的view從主UI線程隊列中pop掉。 一個Android 程序默認情況下也只有一個進程,但一個進程下卻可以有許多個線程。

在這么多線程當中,把主要是負責控制UI界面的顯示、更新和控件交互的線程稱為UI線程,由于onCreate()方法是由UI線程執行的,所以也可以把UI線程理解為主線程。其余的線程可以理解為工作者線程。

invalidate()得在UI線程中被調動,在工作者線程中可以通過Handler來通知UI線程進行界面更新。

Android提供了Invalidate方法實現界面刷新,但是Invalidate不能直接在線程中調用,因為他是違背了單線程模型:Android UI操作并不是線程安全的,并且這些操作必須在UI線程中調用。

簡單說invalidate是在ui線程中使用的。相應的,postinvalidate是在非ui線程里面使用的比如說你用handler刷新,不開新的線程,用invalidate就行了。如果你加載了另外一個線程,就要用postinvalidate。

主要原因是Activity的ui刷新基于單線程模型,非ui線程上的ui操作是不允許的,會報錯。所以在非ui線程上用postinvalidate給ui線程一個訊號,讓ui線程進行刷新操作

使用postInvalidate比較簡單,不需要handler,直接在線程中調用postInvalidate即可,除了onCreate()不是運行在UI線程上的,其實其他大部分方法都是運行在UI線程上的,其實只要你沒有開啟新的線程,你的代碼基本上都運行在UI線程上

再來看postInvalidateOnAnimation的執行過程

InvalidateOnAnimationRunnable本質上是一個Runnable ,run()方法中實際執行view.invalidate方法,也就是說現在的問題是run()怎么執行的,什么時候執行的?!

這里將InvalidateOnAnimationRunnable 做為參數傳給了mChoreographer對象,也就是這里的邏輯就完成了,剩下的invalidate任務交給了mChoreographer。

其中mPosted為true時表示已經通知了mChoreographer來處理刷新的任務,但任務還沒有真正執行,也就在有新的view刷新任務添加時,不再重復通知了。

c.run(frameTimeNanos);這里也就是對應InvalidateOnAnimationRunnable的run()方法。

c是CallbackRecord的實例,CallbackRecord里擁有InvalidateOnAnimationRunnable的實例,即下面代碼中的action;

c.run(frameTimeNanos);中有個時間參數,但((Runnable)action).run();是沒有用到的,可以不關心。

所以現在找定義執行該函數時間的地方。

doCallbacks被doFrame方法調用,doFrame方法執行是在handleMessage中:

而發送MSG_DO_FRAME消息的代碼為:

那么執行時間就由nextFrameTime來決定了。也就是從當前時間開始的10ms內(理論情況)。

這里是沒有使用Vsync同步機制的情況,使用Vsync會增加一些另外的操作,但是最終執行邏輯是一樣的,詳細的分析可參考Android系統Choreographer機制實現過程。

總結一下:

postInvalidate方法是將任務添加到隊列中排隊后立即執行的,而postInvalidateOnAnimation依賴上一幀動畫的的執行時間,因為動畫的刷新是存在一個頻率的,直到下一幀動畫的時間才會真正執行刷新操作。

而postIfNeededLocked()干的事情就是把mInvalidateOnAnimationRunnable作為Choreographer.CALLBACK_ANIMATION(這個類型的task會在mesaure/layout/draw之前被運行)的Task 交給 UI線程的Choreographer.

View的invalidate會進一步觸發ViewRootImpl的invalidateChildInParent()->invalidate()<一種情況(dirty == null 表示全部重繪),不過另外一種差不多>:

不過雖然沒有發出去,不代表這次invalidate就不會生效,因為前面的invalidate()里已經設置了mDirty了:

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容