Android性能优化 - 消除卡顿
性能優(yōu)化系列閱讀
- Android性能優(yōu)化
- 性能優(yōu)化 - 消除卡頓
- 性能優(yōu)化 - 內(nèi)存優(yōu)化
- 性能分析工具 - TraceView
- Android性能分析工具
消除卡頓
- 什么是卡頓及卡頓的衡量標(biāo)準(zhǔn)
- 產(chǎn)生卡頓的原因
- 通用優(yōu)化流程
- 定位卡頓原因
什么是卡頓
卡頓是人的一種視覺感受,比如我們滑動(dòng)界面時(shí),如果滑動(dòng)不流程我們就會(huì)有卡頓的感覺,這種感覺我們需要有一個(gè)量化指標(biāo),在編程時(shí)如果開發(fā)的程序超過了這個(gè)指標(biāo)我們認(rèn)為其是卡頓的。
FPS(幀率):每秒顯示幀數(shù)(Frames per Second)。表示圖形處理器每秒鐘能夠更新的次數(shù)。高的幀率可以得到更流暢、更逼真的動(dòng)畫。一般來說12fps大概類似手動(dòng)快速翻動(dòng)書籍的幀率,這明顯是可以感知到不夠順滑的。30fps就是可以接受的,但是無法順暢表現(xiàn)絢麗的畫面內(nèi)容。提升至60fps則可以明顯提升交互感和逼真感,但是一般來說超過75fps就不容易察覺到有明顯的流暢度提升了,如果是VR設(shè)備需要高于75fps,才可能消除眩暈的感覺。
開發(fā)app的性能目標(biāo)就是保持60fps,這意味著每一幀你只有16ms≈1000/60的時(shí)間來處理所有的任務(wù)。Android系統(tǒng)每隔16ms發(fā)出VSYNC信號(hào),觸發(fā)對(duì)UI進(jìn)行渲染,如果每次渲染都成功,這樣就能夠達(dá)到流暢的畫面所需要的60fps。
如果你的某個(gè)操作花費(fèi)時(shí)間是24ms,系統(tǒng)在得到VSYNC信號(hào)的時(shí)候就無法進(jìn)行正常渲染,這樣就發(fā)生了丟幀現(xiàn)象。那么用戶在32ms內(nèi)看到的會(huì)是同一幀畫面。
如果此時(shí)用戶在看動(dòng)畫的執(zhí)行或者滾動(dòng)屏幕(如RecyclerView),就會(huì)感覺到界面不流暢了(卡了一下)。丟幀導(dǎo)致卡頓產(chǎn)生。
流暢的情況下:
出現(xiàn)了丟幀現(xiàn)象(卡頓)
嚴(yán)重丟幀(卡死了)
給我們一種感覺,如果幀率越低,卡頓就越嚴(yán)重,那么是不是就可以使用幀率來衡量卡頓那?
如何衡量卡頓
FPS的高低不能準(zhǔn)確的反映應(yīng)用的流程度。如下圖所示,只有有更新的時(shí)候才刷新界面。
當(dāng)界面沒有變動(dòng)的時(shí)候,手機(jī)不需要對(duì)界面進(jìn)行更新,所以此時(shí)的FPS會(huì)很低,如果1秒鐘內(nèi)都沒有變動(dòng)那么FPS=0。所以我們需要利用其他方式來衡量應(yīng)用的流程度,比如可以利用丟幀數(shù)來衡量。
單位時(shí)間內(nèi)丟幀數(shù)可以反映出應(yīng)用是否流程。不丟幀是終極目標(biāo),但每秒丟幀在6-7幀左右可以接受,如果丟10幀以上就需要優(yōu)化了。
| 0-10幀 | 流暢 |
| 10-20幀 | 較卡 |
| 20-40幀 | 很卡 |
| 40-60幀 | 卡死了 |
對(duì)于我們開發(fā)人員來說,會(huì)使用一些工具找出卡頓比較集中的地方,找出原因,消除或減弱卡頓。(測(cè)試團(tuán)隊(duì)會(huì)有專門的工具去測(cè)試丟幀的情況)
卡頓產(chǎn)生的原因
核心:分析在16ms中我們的應(yīng)用做了什么工作,那些工作阻止我們?cè)?6ms時(shí)更新界面。
通常情況下,在16ms中我們有那些工作需要處理。
單以XML布局被繪制出來為例進(jìn)行說明。
處理過程:
而實(shí)際開發(fā)中我們還加入交互、業(yè)務(wù)處理等工作,這些工作都需要在16ms中處理完成。對(duì)于開發(fā)人員來說,需要有一個(gè)工具,很直觀的幫助我們判斷出那些工作占用了多少時(shí)間。
Profile GPU Rendering
通過手機(jī)開發(fā)者選項(xiàng)中提供的Profile GPU Rendering(GPU呈現(xiàn)模式分析)功能,我們可以清楚的看到處理流程中各部分的耗時(shí)。手機(jī)端工具(開發(fā)助手àGPU渲染圖)。建議大家在Android6.0及以上手機(jī)測(cè)試。
打開Profile GPU Rendering操作截圖如下:
大家可以拿著真機(jī)配置一下。看看有什么變化。
條形圖說明
Android6.0及以上的手機(jī)顏色對(duì)應(yīng)關(guān)系如下:
原因分析
通用優(yōu)化流程
第一步:UI層優(yōu)化
1、UI問題比較容易查找
2、一旦出現(xiàn)問題影響范圍廣(xml、mesure、layout、draw、Display List 、柵格化……)
工具:設(shè)備過渡繪制查看功能、HierarchyViewer等
常見問題:過渡繪制、布局復(fù)雜、層級(jí)過深……
過渡繪制
在屏幕一個(gè)像素上繪制多次(超過兩次)。如:文本框,如果設(shè)置了背景顏色(黑色),那么顯示的文字(白色)就需要在背景之上再次繪制。
打開手機(jī)開發(fā)者中的過渡繪制區(qū)域即可查看。藍(lán)色標(biāo)識(shí)這個(gè)區(qū)域繪制了兩次。
說明:
設(shè)備中的該選項(xiàng)只能直觀的讓我們感受到應(yīng)用的界面是否存在過渡繪制,如果存在,我們需要利用Hierarchy Viewer查找布局中不合理的地方。
過渡繪制小案例
效果圖如下
大面積存在過渡繪制,文字區(qū)域最嚴(yán)重。查詢Item布局文件找出過渡繪制的原因
自定義控件繪制優(yōu)化
Clip Rect 與 Quick Reject
- Clip Rect:識(shí)別可見區(qū)域
- Quick Reject:控件所在的矩形區(qū)域是否有交集
在Canvas中有上述兩個(gè)方法,幫助我們進(jìn)行判斷,避免出現(xiàn)過渡繪制。
我們可以通過canvas.clipRect()來幫助系統(tǒng)識(shí)別那些可見的區(qū)域,在這個(gè)區(qū)域之外的我們不在進(jìn)行繪制。如側(cè)拉菜單,當(dāng)菜單顯示的時(shí)候被菜單遮擋的部分是不用進(jìn)行繪制的,一旦繪制就會(huì)出現(xiàn)過渡繪制現(xiàn)象。系統(tǒng)的控件會(huì)控制過渡繪制,但我們自己的控件就需要自行管理了。所以在使用側(cè)拉菜單時(shí)就需要優(yōu)先考慮系統(tǒng)提供的了。
如果系統(tǒng)沒有提供的,我們自己編寫時(shí)也需要注意,避免出現(xiàn)過渡繪制。
自定義控件過渡繪制
案例效果
編寫自定義控件MyVIew,在布局中引入該控件
<com.itheima.overdrawdemo.MyView android:layout_width="match_parent"android:layout_height="match_parent"android:background="@android:color/transparent"> </com.itheima.overdrawdemo.MyView>圖片資源數(shù)組
private int[] ids = new int[]{R.drawable.img1, R.drawable.img2, R.drawable.img3, R.drawable.img4, R.drawable.img5, R.drawable.img6};初始化時(shí)加載圖片資源,同時(shí)對(duì)一會(huì)需要使用到的畫筆做初始化
private void init() {for (int i = 0; i < 6; i++) {imgs[i] = BitmapFactory.decodeResource(getResources(), ids[i]);}paint=new Paint();paint.setAntiAlias(true); }先將圖片擺放好
for (int i = 0; i < imgs.length; i++) {canvas.drawBitmap(imgs[i],i*20,0,paint); }通過過渡繪制的開啟,觀察結(jié)果
原因比較簡(jiǎn)單,對(duì)于“大王”這張牌來說,我們不需要繪制完整的圖片,如果都繪制了就會(huì)出現(xiàn)上面的情況
處理思路:找出牌需要繪制的區(qū)域,讓canvas在繪制這張牌時(shí)僅僅按區(qū)域繪制一部分即可。對(duì)于“大王”這張牌來說我們僅僅繪制如下內(nèi)容
重點(diǎn)來了,我們?cè)撊绾蝿澏ㄟ@個(gè)區(qū)域? 在Canvas中clipRect方法可以幫助我們劃定一個(gè)區(qū)域,進(jìn)行繪制。
方法參數(shù)說明:
clipRect(int left, int top, int right, int bottom) canvas.clipRect(0, 0, 20, imgs[i].getHeight());設(shè)置完成后,我們來繪制大王這張牌。
canvas.drawBitmap(imgs[0],0,0,paint);再增加循環(huán),快速繪制所有的牌。
for (int i = 0; i < imgs.length; i++) {canvas.clipRect(i * 20, 0, (i + 1) * 20, imgs[i].getHeight());canvas.drawBitmap(imgs[i],i*20,0,paint); }大家會(huì)發(fā)現(xiàn)繪制完成的結(jié)果不是我們想要的。
我們需要借助save和restore來完成裁剪的操作。
save:用來保存Canvas的狀態(tài)。save之后,可以調(diào)用Canvas的平移、放縮、旋轉(zhuǎn)、錯(cuò)切、裁剪等操作。
restore:用來恢復(fù)Canvas之前保存的狀態(tài)。防止save后對(duì)Canvas執(zhí)行的操作對(duì)后續(xù)的繪制有影響。
save和restore要配對(duì)使用(restore可以比save少,但不能多),如果restore調(diào)用次數(shù)比save多,會(huì)引發(fā)Error。save和restore之間,往往夾雜的是對(duì)Canvas的特殊操作
代碼修改如下
for (int i = 0; i < imgs.length; i++) {canvas.save();canvas.clipRect(i * 20, 0, (i + 1) * 20, imgs[i].getHeight());canvas.drawBitmap(imgs[i],i*20,0,paint);canvas.restore(); }效果如下
剩下最后一個(gè)工作,把最上面的牌繪制完整
for (int i = 0; i < imgs.length; i++) {canvas.save();if(i<imgs.length-1) {canvas.clipRect(i * 20, 0, (i + 1) * 20, imgs[i].getHeight());}else if(i==imgs.length-1){canvas.clipRect(i * 20, 0, i * 20+imgs[i].getWidth(), imgs[i].getHeight());}canvas.drawBitmap(imgs[i],i*20,0,paint);canvas.restore(); }Hierarchy Viewer(層級(jí)查看器)工具使用
Hierarchy Viewer可以很直接的呈現(xiàn)布局的層次關(guān)系,視圖組件的各種屬性。我們可以通過紅,黃,綠三種不同的顏色來區(qū)分布局的Measure,Layout,Executive的相對(duì)性能表現(xiàn)如何。
打開工具
選擇需要查看的內(nèi)容
查看各個(gè)節(jié)點(diǎn)Measure,Layout,Executive
三個(gè)小圓點(diǎn), 依次表示Measure, Layout,Draw, 可以理解為對(duì)應(yīng)View的onMeasure, onLayout, onDraw三個(gè)方法
綠色:表示該View的此項(xiàng)性能比該View Tree中超過50%的View都要快
黃色:表示該View的此項(xiàng)性能比該View Tree中超過50%的View都要慢
紅色:表示該View的此項(xiàng)性能是View Tree中最慢的
一般來說
Measure紅點(diǎn), 可能是布局中嵌套R(shí)elativeLayout, 或是嵌套LinearLayout都使用了weight屬性.
Layout紅點(diǎn), 可能是布局層級(jí)太深
Draw紅點(diǎn), 可能是自定義View的繪制有問題, 復(fù)雜計(jì)算等
我們之前的小案例,可以進(jìn)行層級(jí)優(yōu)化
常規(guī)做法
沒有用的父布局——沒有背景繪制或沒有大小限制的父布局,不會(huì)對(duì)界面效果產(chǎn)生任何影響。特別是進(jìn)來的布局,很容易產(chǎn)生問題。可以通過標(biāo)簽替代。
在布局層次一樣的情況下,建議使用LinearLayout代替RelativeLayout。
使用LinearLayout導(dǎo)致的層次變深,可以使用RelativeLayout進(jìn)行替換。同樣的界面我們可以使用不同的方式去實(shí)現(xiàn),選擇一個(gè)層級(jí)最少的方案。
不常用的UI被設(shè)置成了GONE,嘗試使用代替。
去掉多余的背景顏色,減少過渡繪制,對(duì)于有多層背景色的布局來說,留最上面的一層即可。謹(jǐn)慎使用alpha,如果后渲染的元素有設(shè)置alpha值,那么這個(gè)元素就會(huì)和屏幕上已經(jīng)渲染好的元素做blend處理,這樣會(huì)導(dǎo)致不少性能問題,特別是出現(xiàn)在列表的Item中。
對(duì)于使用Selector當(dāng)背景的布局,可以將normal狀態(tài)的color設(shè)置為透明。
我們不能因?yàn)樘岣咝阅芏雎粤私缑嫘枰_(dá)到的效果(平衡Design與Performance)
第二步:代碼問題查找
工具:Lint
常見問題:我們重點(diǎn)關(guān)注Performance和Xml中的一些建議
- 在繪制時(shí)實(shí)例化對(duì)象(onDraw)
- 手機(jī)不能進(jìn)入休眠狀態(tài)(Wake lock)
- 資源忘記回收
- Handler使用不當(dāng)?shù)怪脙?nèi)存泄漏
- 沒有使用SparseArray代替HashMap
- 未被使用的資源
- 布局中無用的參數(shù)
- 可優(yōu)化布局(如:ImageView與TextView的組合是否可以使用TextView獨(dú)立完成)
- 效率低下的 無用的命名空間等
Lint工具使用
Android Studio中開啟Lint工具
選中需要分析的Module,點(diǎn)擊工具欄中Analyze中的Inspect Code選項(xiàng)。
選擇需要分析的Module或整個(gè)項(xiàng)目
我們可以逐一閱讀一下,但是重點(diǎn)關(guān)注性能問題,xml中的一些問題也盡可能進(jìn)行修復(fù)。
問題處理
1、案例中性能問題處理
其他的一些性能問題
建議使用concate方法進(jìn)行連接字符串,會(huì)比append的方式性能好。
2、案例中xml提到的內(nèi)容如下
其他問題:
無效的命名空間
無效的布局參數(shù)
比如在線性布局中的控件使用到了相對(duì)布局中的屬性,運(yùn)行時(shí)需要處理,影響代碼的執(zhí)行效率。
3、案例中關(guān)于定義聲明變量的警告
意見或建議
- 不斷關(guān)注Lint中提到的問題,將公司中命名規(guī)范中沒有提到的內(nèi)容逐一補(bǔ)全。
- Lint不是萬能的。
第三步:優(yōu)化App的邏輯層
工具:Traceview
常見問題:主線程耗時(shí)大的函數(shù)、滑動(dòng)過程中的CPU工作問題,工具可以提供每個(gè)函數(shù)的耗時(shí)和調(diào)用次數(shù),我們重點(diǎn)關(guān)注兩種類型的函數(shù):
使用Traceview找出卡住主線程的地方
Traceview工具使用
通過Android Studio打開里面的Android Device Monitor,切換到DDMS窗口,點(diǎn)擊左邊欄上面想要跟蹤的進(jìn)程,再點(diǎn)擊上面的Start Method Profiling的按鈕,如下圖所示:
啟動(dòng)跟蹤之后,再操控app,做一些你想要跟蹤的事件,例如滑動(dòng)RecyclerView,點(diǎn)擊某些視圖進(jìn)入另外一個(gè)頁(yè)面等等。操作完之后,回到Android Device Monitor,再次點(diǎn)擊相同的按鈕停止跟蹤。此時(shí)工具會(huì)為剛才的操作生成TraceView的詳細(xì)視圖。
重點(diǎn)關(guān)注Incl Cpu Time、Call+Recur Calls/Total、Real Time/Call
通過降序排序,我們可以分別找到這兩列中數(shù)值比較大的內(nèi)容。
指標(biāo)說明:
| Incl(Inclusive) Cpu Time | 方法本身和其調(diào)用的所有子方法占用CPU時(shí)間 |
| Excl(Exclusive) Cpu Time | 方法本身占用CPU時(shí)間 |
| Incl Real Time | 方法(包含子方法)開始到結(jié)束用時(shí) |
| Excl Real Time | 方法本身開始到結(jié)束用時(shí) |
| Call + Recursion Calls/Total | 方法被調(diào)用次數(shù) + 方法被遞歸調(diào)用次數(shù) |
| Cpu Time/Call | 方法調(diào)用一次占用CPU時(shí)間. 方法實(shí)際執(zhí)行時(shí)間(不包括io等待時(shí)間) |
| Real Time/Call | 方法調(diào)用一次實(shí)際執(zhí)行時(shí)間. 方法開始結(jié)束時(shí)間差(包括等待時(shí)間) |
小案例:
我們可以在ViewHolder的設(shè)置數(shù)據(jù)中做點(diǎn)手腳,比如睡幾毫秒(8ms),通過監(jiān)控滾動(dòng),我們是否可以定位到問題代碼。
好的做法
AsyncTask:為UI線程與工作線程之間進(jìn)行快速的切換提供一種簡(jiǎn)單便捷的機(jī)制。適用于當(dāng)下立即需要啟動(dòng),但是異步執(zhí)行的生命周期短暫的使用場(chǎng)景。
HandlerThread: 為某些回調(diào)方法或者等待某些任務(wù)的執(zhí)行設(shè)置一個(gè)專屬的線程,并提供線程任務(wù)的調(diào)度機(jī)制。
ThreadPool: 把任務(wù)分解成不同的單元,分發(fā)到各個(gè)不同的線程上,進(jìn)行同時(shí)并發(fā)處理。
IntentService: 適合于執(zhí)行由UI觸發(fā)的后臺(tái)Service任務(wù),并可以把后臺(tái)任務(wù)執(zhí)行的情況通過一定的機(jī)制反饋給UI。
如果大量操作數(shù)據(jù)庫(kù)數(shù)據(jù)時(shí)建議使用批處理操作。如:批量添加數(shù)據(jù)。
綜合案例
應(yīng)用啟動(dòng)性能優(yōu)化。
使用NoHttp獲取應(yīng)用列表
問題表現(xiàn):通常從用戶點(diǎn)擊到應(yīng)用完全展示完首頁(yè),需要用戶等待一段時(shí)間。我們?nèi)绾慰s短時(shí)間并提高用戶體驗(yàn)。
分析:應(yīng)用在啟動(dòng)的過程中我們的代碼能夠影響啟動(dòng)速度的地方如下
- Application的onCreate
- 首屏Activity的渲染
步驟:
利用Traceview工具觀察啟動(dòng)過程方法耗時(shí)情況,重點(diǎn)關(guān)注onCreate方法(自定義Application和首頁(yè)Activity)。問題:Traceview工具如何在應(yīng)用啟動(dòng)時(shí)監(jiān)控?cái)?shù)據(jù)?
分析自定義Application耗時(shí)操作,判斷onCreate方法中的內(nèi)容(如:第三方的工具是否可以不占用主線程進(jìn)行初始化)。
查看界面是否存在過渡繪制。
利用Hierarchy Viewer工具查看界面需要優(yōu)化的點(diǎn)。
啟動(dòng)過程中的白屏優(yōu)化。
第一步:觀察耗時(shí)情況
1、在onCreate開始和結(jié)尾打上trace
Debug.startMethodTracing("POApp"); Debug.stopMethodTracing();運(yùn)行程序, 會(huì)在sdcard上生成一個(gè)”POApp.trace”的文件.
注意:需要給程序加上寫存儲(chǔ)的權(quán)限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>Android6.0以后的模擬器需要為應(yīng)用打開讀寫權(quán)限
2、通過adb pull將其導(dǎo)出到本地
adb pull /sdcard/ POApp.trace 存放文件路徑第二步:分析數(shù)據(jù)
通過DDMS的FileàOpen File
查詢結(jié)果如下
說明:我們使用Real Time/Call進(jìn)行排序可以得到上圖內(nèi)容
大家可以發(fā)現(xiàn)在Application中阻塞主線程干的工作都是NoHttp的初始化工作。為了提高應(yīng)用的啟動(dòng)速度,我們可以將這個(gè)工作放到子線程中完成,通常我們會(huì)使用IntentService來處理這個(gè)工作。
代碼如下:
/*** Created by itheima.*/public class MyApplication extends Application {@Overridepublic void onCreate() {// 如果沒有辦法手動(dòng)操作監(jiān)控,可以使用如下代碼重點(diǎn)關(guān)注我們感興趣的方法// 監(jiān)控的結(jié)果會(huì)生成文件存儲(chǔ)SDCard上 // Debug.startMethodTracing("AppStartupDemo");// 文件的名稱super.onCreate();InitService.start(this);SystemClock.sleep(1000);// Debug.stopMethodTracing();} } /*** 將MyApplication中onCreate方法內(nèi)容耗時(shí)的初始化工作移動(dòng)到該類中*/public class InitService extends IntentService {// 問題:由于將NoHttp的初始化工作移動(dòng)到了子線程,當(dāng)主線程使用NoHttp發(fā)現(xiàn)沒有初始化完成,報(bào)異常了。// 方案一:使用boolean值進(jìn)行初始化工作的標(biāo)記,如果完成boolean為true,可以在使用該工具的地方每隔一個(gè)時(shí)間段判斷一下。// 方案二:當(dāng)初始化工作完成后,發(fā)出一個(gè)通知,如果有觀察者,則進(jìn)行后續(xù)工作的處理public static boolean isInit=false;// 標(biāo)記是否初始化完成public InitService() {super("init");}@Overrideprotected void onHandleIntent(@Nullable Intent intent) {// 耗時(shí)操作Logger.setTag("NoHttp");Logger.setDebug(true);NoHttp.initialize(this, new NoHttp.Config().setConnectTimeout(30 * 1000).setReadTimeout(30 * 1000));isInit=true;}/*** 啟動(dòng)service* @param myApplication*/public static void start(MyApplication myApplication) {Intent intent = new Intent(myApplication, InitService.class);myApplication.startService(intent);} }修改完成后,會(huì)引發(fā)一個(gè)問題,及在首頁(yè)訪問網(wǎng)絡(luò)時(shí),由于NoHttp的初始化還沒有完成會(huì)報(bào)出如下異常:
如果我們?cè)谑醉?yè)就需要立即訪問網(wǎng)絡(luò),就需要對(duì)初始化進(jìn)行監(jiān)控,可以簡(jiǎn)單的使用一個(gè)boolean值,進(jìn)行判斷,當(dāng)初始化完成后boolean值修改為true。我們?cè)贛ainActivity中可以使用Handler間隔一段時(shí)間就檢查一下boolean即可。
第三步:過渡繪制
進(jìn)入首頁(yè)后,應(yīng)用的啟動(dòng)速度限制就集中在首頁(yè)的界面渲染上了。因此我們開始對(duì)界面進(jìn)行優(yōu)化處理。
過渡繪制查看結(jié)果。
表現(xiàn)還好,我們可以檢查一下Item,看看是否可以優(yōu)化掉一次繪制。
第四步:優(yōu)化界面布局
Hierarchy Viewer工具派上用場(chǎng)了,我們可以檢查一下布局是否合理。
重點(diǎn)觀察其中一個(gè)條目
優(yōu)化完成后的結(jié)構(gòu)圖
我們先優(yōu)化掉兩個(gè)用處不大的LinearLayout,然后在考慮是否可以繼續(xù)優(yōu)化掉條目中的LinearLayout。
第五步:Launch screens設(shè)置
兩種處理方案:
方案一:設(shè)置一個(gè)背景圖
<item name="android:windowBackground">@drawable/splash</item> <item name="android:windowNoTitle">true</item>注意:當(dāng)界面加載完成后需要將背景改成白色。
方案二:設(shè)置成透明的界面,制造延時(shí)啟動(dòng)效果
<item name="android:windowIsTranslucent">true</item> <item name="android:windowNoTitle">true</item>AndroidPerformanceMonitor
GitHub BlockCanary — 輕松找出Android App界面卡頓元兇
BlockCanary是一個(gè)Android平臺(tái)的一個(gè)非侵入式的性能監(jiān)控組件,應(yīng)用只需要實(shí)現(xiàn)一個(gè)抽象類,提供一些該組件需要的上下文環(huán)境,就可以在平時(shí)使用應(yīng)用的時(shí)候檢測(cè)主線程上的各種卡慢問題,并通過組件提供的各種信息分析出原因并進(jìn)行修復(fù)。
取名為BlockCanary則是為了向LeakCanary致敬,順便本庫(kù)的UI部分是從LeakCanary改來的,之后可能會(huì)做一些調(diào)整。
總結(jié)
以上是生活随笔為你收集整理的Android性能优化 - 消除卡顿的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android性能优化 - 内存优化
- 下一篇: TextureView+MediaPla