概述
BlockCanary是Android平臺上的一個輕量的,非侵入式的性能監控組件,可以在使用應用的時候檢測主線程上的各種卡頓問題,并可通過組件提供的各種信息分析出原因并進行修復。
使用
Step1. 配置build.gradle
dependencies {
// most often used way, enable notification to notify block event
implementation 'com.github.markzhai:blockcanary-android:1.5.0'
// this way you only enable BlockCanary in debug package
// debugImplementation 'com.github.markzhai:blockcanary-android:1.5.0'
// releaseImplementation 'com.github.markzhai:blockcanary-no-op:1.5.0'
}
Step2. 在Application中注冊
public class DemoApplication extends Application {
@Override
public void onCreate() {
// ...
// Do it on main process
BlockCanary.install(this, new BlockCanaryContext()).start();
}
}
Step3. 檢測結果
blockcanary-result.png
原理
在Android中,應用的卡頓,主要是在主線程阻塞導致的。Looper是主線程的消息調度者,所以以它為突破點。
Looper#loop():
在Looper的loop方法中,有一個Printer,它在每個Message處理的前后被調用,而如果主線程卡住了,就是
dispatchMessage
里卡住了。
public static void loop() {
// ....
for (;;) {
// ...
// This must be in a local variable, in case a UI event sets the logger
final Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
// ...
msg.target.dispatchMessage(msg);
// ...
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// ...
}
}
獲取主線程的Looper:
因為Looper在每個線程最多只有一個實例,所以只要獲取到主線程的Looper,就可以設置一個自定義的Printer對象到里面。
Looper mainLooper = Looper.getMainLooper();
創建自定義Printer
在Printer的println方法去計算主線程一條Message處理的時長,當時長超過設定的閾值時就判定是卡頓了。
...
@Override
public void println(String x) {
if (!mStartedPrinting) {
mStartTimeMillis = System.currentTimeMillis();
mStartThreadTimeMillis = SystemClock.currentThreadTimeMillis();
mStartedPrinting = true;
} else {
final long endTime = System.currentTimeMillis();
mStartedPrinting = false;
if (isBlock(endTime)) {
notifyBlockEvent(endTime);
}
}
}
private boolean isBlock(long endTime) {
return endTime - mStartTimeMillis > mBlockThresholdMillis;
}
...
設置自定義Printer到主線程Looper:
Looper.getMainLooper().setMessageLogging(mainLooperPrinter);
流程圖:
blockcanary-flow.png
參考鏈接
編碼前線.jpg