感覺這是一個很有意思的工具,可以檢測UI線程處理每個message時間。如果時間長了,那么就發個通知,通知開發者哪里可能存在問題。原理并不難,不過作者能想出來這種方法來檢測手機app的一些性能問題,還是挺有心的,應該給作者點個贊。
開源庫的地址是 戳這里
哪些卡頓檢查不出來
首先說下這個工具只能檢測一些性能問題。卡頓的問題不只是因為message的執行時間過長。比如:界面的渲染是在Render Thread線程。主線程會把view#draw()方法的指令解析成GPU能讀懂的指令,然后傳給Render Thread線程。 GPU再根據這些指令進行渲染。繪制是一個很復雜的過程。雖然有了Render Thread線程來做渲染工作,大部分時間Render Thread 和主線程是并發進行的,但是還是會有一個點 兩個線程是互相依賴的。他們需要相互等待來交換數據,以便將數據寫入到 back buffer中。back buffer是從SurfaceFlinger 服務的buffer隊列請求來的。當把渲染的數據寫到back buffer后,會返回給SurfaceFlinger 服務的buffer隊列。SurfaceFlinger會根據硬件屏幕刷新時鐘Async來把buffer(這里叫frame buffer)給到android系統中進行屏幕展示。這里的要展示的frame buffer來自于back buffer。所以如果繪制不及時(>16ms), back buffer在16ms內沒有裝載完畢。那么SurfaceFlinger只能把之前的back buffer當成frame buffer提交給屏幕進程呈現。因此卡頓就產生了。
因此,繪制不及時有很多種。比如上面說的Render Thread線程繪制了一個很復雜的view(比如給view添加蒙層,就會導致繪制的復雜),因為主線程與Render Thread線程存在依賴,那么主線程需要等待,導致back buffer不能完成,進而產生卡頓。這時候UI線程中處理msg的時間并不長,只是一直在block等待。這種卡頓AndroidPerformanceMonitor并不能處理。
原理分析
原理就不貼代碼了,幾句話就能說完。貼代碼反而影響問題的闡述。
我們知道,主線程的Looper工作在一個for循環中,每次從隊列中拿到一個meesage進行處理。在處理每一個message時,在開始處理,到處理完成都會使用Printer來打印一些東西。開始時打印:
'' logging.println(">>>>> Dispatching to " + msg.target + " " +
'' msg.callback + ": " + msg.what);
結束時打印:
'' logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
這個Printer是Looper的mLogging成員變量,我們可以設置。原理就在這里。我們可以設置一個自定義的Printer。重寫Printer的println(String)方法。在重寫的println(String)方法中判斷,如果參數string中包含“Dispatching to”,那么就往HandleThread線程的隊列中添加一個延時300ms的runnable,runnable中處理卡頓信息的邏輯。如果判斷參數string中包含“Finished“,那么如果HandleThread線程的隊列 中的runnable還在,就清除這個runnable。即,說明這個message執行完還不到300ms,那么就認為處理這個message沒有發生卡頓。當然如果打印”Finished“時,與”Dispatching“的時間差已經大于了300ms,那么runnable便已經執行了處理卡頓信息的邏輯。
大致原理就是這樣。