在一个应用进程中只有一个MainLooper, 在looper的loop方法中,存在一个
Printer logging = me.mLogging;
在dispatchMessage方法前后会调用,logging.println();
因此,可以通过设置自定义的Printer来监控dispatchMessage是否出现了异常。
Looper.java
public static void loop() {
final Looper me = myLooper();
。。。
final MessageQueue queue = me.mQueue;
。。。
for (;;) {
Message msg = queue.next(); // might block
。。。
// 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);
}
。。。
try {
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
}
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
这个Printer初始化是空的,我们可以通过以下代码来设置自定的Printer,通过前后两次执行println方法的时间差来判断是否卡顿。另外可以启动一个线程来定时采样线程信息,用来提供卡顿时的线程数据。
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
在监控anr的时候,由于第二次dispatchMessage造成阻塞,无法执行,第二次logging.println,因此可以在println中给anr线程设置一个标志位,等dispatchMessage执行后,第二次执行println中的标志位复位,而在anr线程中,如果标志位超过时间没有复位,则视为发生了anr,可以收集信息上报了。
IMG_0285.JPGps: 收集信息上报,可以先将信息保存在本地,等一定数量后压缩,上传服务器。
refer: 性能优化最佳实践
系统anr原理
跟监控原理是类似的
image.png
网友评论