android刷新ui
Ⅰ android中如何實現UI的實時更新
1、在主線程中啟動一個子線程
首先,我們需要在主線程中啟動一個子線程,這個比較簡單,直接在MainActivity的onCreate()方法中調用如下方法即可:
java">newThread(mRunnable).start();
2、在子線程中發送Message給Handler
在創建子線程時,我們使用了Runnable介面對象mRunnable。這里,只需要實現Runnable介面,並重寫該介面的run()方法,在run()方法中實現每1秒發送一條Message給Handler即可。具體實現方法如下:
/*
*Function:實現run()方法,每1秒發送一條Message給Handler
*/
privateRunnablemRunnable=newRunnable(){
publicvoidrun(){
while(true){
try{
Thread.sleep(1000);
mHandler.sendMessage(mHandler.obtainMessage());
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
}
};
3、Handler接收Message通知
最後,我們創建一個Handler對象,用來接收Message通知。在收到Message通知後,完成刷新UI的操作即可。具體實現方法如下:
/*
*Function:實現handleMessage()方法,用於接收Message,刷新UI
*/
privateHandlermHandler=newHandler(){
publicvoidhandleMessage(Messagemsg){
super.handleMessage(msg);
refreshUI();
}
};
4、刷新UI
由以上的代碼可以看出,刷新UI的操作,我們是放在refreshUI()方法中來完成的。refreshUI()方法的實現也很簡單,調用HttpUtils工具類中的getInputStream()方法,獲得圖1所示Web工程的頁面內容輸入流,再將該輸入流轉化為字元串,放入TextView控制項中進行顯示即可。具體實現方法如下:
/*
*Function:刷新UI
*/
privatevoidrefreshUI(){
try{
InputStreaminputStream=HttpUtils.getInputStream();
StringresultData=HttpUtils.getResultData(inputStream);
mTextView.setText(resultData);
}catch(IOExceptione){
e.printStackTrace();
}
}
Ⅱ androidUI卡頓原理分析及Vsync信號機制
一、UI卡頓定義
1、用戶角度:app操作界面刷新緩慢,響應不及時;界面滑動不夠流暢;
2、系統角度:屏幕刷新幀率不穩定,掉幀嚴重,無法保證每秒60幀,導致屏幕畫面撕裂;
二、UI卡頓常見原因分析以及處理方案
1、過度繪制:
原因:界面布局設計不合理或者過於復雜導致系統無法在16毫秒內完成渲染,view過度繪制導致CPU或者GPU負載過重,View頻繁觸發measure、layout操作,導致measure、layout累計耗時嚴重以及整個View錯誤的頻隱讓繁重新渲染;
方案:優化界面布局,使界面布局視圖扁平化,去除不必要的背景顏色,減少透明色的使用;
方案依據原理:盡量減少View在系統中measure、layout、draw的累計時間;
2、UI線程的復雜運算
原因:UI主線程運算耗時
方案:減少UI線程中數據運算,使用子線程處理耗時任務
3、頻繁GC
原因:(1)、內存抖動;(2)、瞬間產生大量對象,消耗內存;
方案:盡量避免在循環邏輯或者onDraw方法中頻繁創建新對象和使用局部變數;
三、android Vsync機制
1、什麼是Vsync ?
Vsync 是Vertical Synchronization(垂直同步)的縮寫,是一種在PC上很早就廣泛使用的技術,可則慶以簡單的把它認為是一種定時中斷。而在Android 4.1(JB)中已經開始引入VSync機制,用來同步渲染,讓孫攜握AppUI和SurfaceFlinger可以按硬體產生的VSync節奏進行工作。
2、Android屏幕刷新過程
Android系統每隔16ms發出VSYNC信號,觸發對UI進行渲染,屏幕的刷新過程是每一行從左到右(行刷新,水平刷新,Horizontal Scanning),從上到下(屏幕刷新,垂直刷新,Vertical Scanning)。當整個屏幕刷新完畢,即一個垂直刷新周期完成,會有短暫的空白期,此時發出 VSync 信號。所以,VSync 中的 V 指的是垂直刷新中的垂直-Vertical。
3、沒有使用Vsync的情況
可見vsync信號沒有提醒CPU/GPU工作的情況下,在第一個16ms之內,一切正常。然而在第二個16ms之內,幾乎是在時間段的最後CPU才計算出了數據,交給了Graphics Driver,導致GPU也是在第二段的末尾時間才進行了繪制,整個動作延後到了第三段內。從而影響了下一個畫面的繪制。這時會出現Jank(閃爍,可以理解為卡頓或者停頓)。這時候CPU和GPU可能被其他操作佔用了,這就是卡頓出現的原因;
4、使用Vsync同步
CPU/GPU接收vsync信號,Vsync每16ms一次,那麼在每次發出Vsync命令時,CPU都會進行刷新的操作。也就是在每個16ms的第一時間,CPU就會響應Vsync的命令,來進行數據刷新的動作。CPU和GPU的刷新時間,和Display的FPS是一致的。因為只有到發出Vsync命令的時候,CPU和GPU才會進行刷新或顯示的動作。CPU/GPU接收vsync信號提前准備下一幀要顯示的內容,所以能夠及時准備好每一幀的數據,保證畫面的流暢;
5、多級緩沖
Android除了使用Vsync機制,還使用了多級緩沖的策略來優化屏幕顯示,如雙重緩沖(A + B),當Display buffer A 數據時,CPU/GPU就已經在buffer B 中處理下一幀要顯示的數據了。
可是,當系統資源緊張性能降低時,導致GPU在處理某幀數據時太耗時,在Vsync信號到來時,buffer B的數據還沒准備好,此時不得不顯示buffer A的數據,這樣導致後面CPU/GPU沒有新的buffer准備數據,空白時間無事可做,後面Jank頻出
因此採用三級緩沖來解決系統對性能不穩定導致的卡頓
當出現上面所述情況後,新增一個buffer C 可以減少CPU和GPU在Vsync同步間的空白間隙,此時CPU/GPU能夠利用buffer C 繼續工作,後面buffer A 和 buffer B 依次處理下一幀數據。這樣僅是產生了一個Jank,可以忽略不計,以後的流程就順暢了。
註:在多數正常情況下還是使用二級緩沖機制,三級緩沖只是在需要的時候才使用;
Ⅲ Android UI線程
思考:
先必須了解下面2個問題
1.顧名思義 UI線程 就是刷新UI 所在線程
2.UI是單線程刷新
1.對Activity 來說 UI線程就是其主線程
2.對View來說 UI線程就是創建ViewRootImpl所在的線程
可以通過 WindowManager 內部會創建ViewRootImpl對象
好了,進入主題。我們來慢慢揭開面紗。
我們可以分別從幾個方面切入
我們可能都有使用過 runOnUiThread 現在來看看的源碼實現。
可以從上面的源碼 看到
不是UI線程 就用Handler切到Handler所在的線程中,如果是UI線程直接就調用run方法。
Activity的創建:
1.Activity創建:mInstrumentation.newActivity
2.創建Context :ContextImpl (r)
我們經常用這個方法乾的事情就是,要麼在onCreate中獲取View寬高的值。要麼就是在子線程中做一些耗時操作 ,然後post切到對應View所在的線程 來繪制UI操作。那麼這個對應的線程就是UI線程了。
那麼這個UI線程就一定是主線程嗎?
接來繼續來看。它的源碼View:post
mAttachInfo 在dispatchAttachedToWindow 中被賦值 ,也就是在ViewRootImpl創建的時候,所以是創建ViewRootImpl所在的線程。
attachInfo 上面時候為null 呢?在ViewRootImpl 還沒來得及創建的時候,ViewRootImpl 創建是在 「onResume" 之後。所以在 Activity 的 onCreate 去View.post 那麼AttachInfo 是為null 。
當 AttachInfo == null 那麼會調用 getRunQueue().post(action) 。
最終這個Runnable 被 緩存到 HandlerActionQueue 中。
直到ViewRootImpl 的 performTraversals 中 調用dispatchAttachedToWindow(mAttachInfo, 0);, 那麼才會去處理 RunQueue() 中的Runnable。
來張圖 便於理解這個流程
我們有時候去子線程操作UI的時候(如:requestLayout),會很經常見到下面的 報錯日誌:
Only the original thread that created a view hierarchy can touch its views
為什麼會報這個錯誤呢?
翻譯一下:只有創建視圖層次結構的原始線程才能接觸到它的視圖。
也就是操作UI的線程要和ViewRootImpl創建的線程是同一個線程才行,並不是只有主線程才能更新UI啊。
ViewRootImpl創建的線程?那麼 ViewRootImpl 在哪裡被創建的呢?
從上圖可以看到ViewRootImpl創建最開始是從 ActivityThread 的HandleResumeActivity中開始 一直 ViewRootImpl 創建,也就是說ViewRootImpl 對應的UI線程和 ActivityThread 在同一個線程 也就是主線程。
好了 通過上面的講解,上面的問題相信你可以自己回答啦~
Ⅳ Android UI刷新機制
Android屏幕的刷新包含3個步驟:CPU計算屏幕數據、GPU進一步處理和緩存、最後屏幕(Display)再從緩存中把計算的屏幕數據顯示出來
對於 Android 而言,第一個步驟搜納: CPU 計算屏幕數據 指的也就是 View 樹的繪制過程,也就是 Activity 對應的視圖樹從根布局 DecorView 開始層層遍歷每個 View,分別執行測量、布局、繪制三個操作的過程。我們重點分析的也是這個步驟,關於後續的2個步驟我們可以理解為底層處理,沒必要過於深入。
我們知道Android每隔16.6ms會發送一次垂直同步VSync信息量,1S也就是60幀的畫面。下面這個圖藍色的是CPU計算屏幕數據時間戳,綠色的是GPU的處理,最後黃色的是屏幕。我們可以清楚的看到,每幀的畫面都會提前一幀去計算以及GPU處理。
如果我們保持頁面靜止,那梁橡么Android還是會16.6ms發送一次垂直同步信號量,App這個時候接受不到屏幕刷新的信號。所以也就不會讓 CPU 去計算下一幀畫面數據,但是底層仍然會以固定的頻率來切換每一幀的畫面,只是它後面切換的每一幀畫面都一樣,所以給我們的感覺就是屏幕沒刷新
我們世渣沒都知道Android的刷新離不開ViewRootImpl,在上一篇文章 《Android中UI的繪制流程》 中,大致闡述了Android的UI刷新流程。這里我們進一步深入的理解源碼,以及刷新UI的詳細流程。首先看圖:
Ⅳ Android中Fragment怎樣刷新UI
刷新UI要在主線程,Fragment和Activity是類似的,所以在要刷新UI的地方handler發送消息,在主線程中定義的hanler處理消息,更新UI,建議看下安卓的安卓handler機制。