一:常见方案
1 通过UI 线程looper
2 通过Choreographer
1.1 通过UI 线程looper的打印日志
在github上也有许多开源库是基于该原理,比较有代表行的有
通过如下代码可以看到,只存在一个主线程的Looper,所有通过主线程Handler发送的消息,都会发送到这里。
/**
* Initialize the current thread as a looper, marking it as an
* application's main looper. The main looper for your application
* is created by the Android environment, so you should never need
* to call this function yourself. See also: {@link #prepare()}
*/
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
/**
* Returns the application's main looper, which lives in the main thread of the application.
*/
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
继续仔细观察Looper的源码可以发现,msg.target.dispatchMessage(msg); 这句用来进行消息的分发处理,在处理前后分别会打印日志,如果我们在消息处理之前计一个时,在消息处理之后计算一个值,如果这两者的阈值,大于了我们设定的门限,那么就可以认为卡顿。
public static void loop() {
final Looper me = myLooper();
...
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
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);
}
...
}
}
但是MainLooper里面的默认打印的消息,并没有记录时间,这时,我们需要通过Looper.setMessageLogging来设置自定义的 Printer 。
Looper mainLooper = Looper.getMainLooper();
mainLooper.setMessageLogging(new MyPrinter());
自定义MyPrinter 实现Printer重新println
public class MyPrinter implements Printer {
private static final String TAG = MyPrinter.class.getSimpleName();
private boolean printerStart = true;
private long startTime;
private long endTime;
@Override
public void println(String x) {
if (printerStart) {
startTime = System.currentTimeMillis();
Log.e(TAG,"current startTime: " + startTime);
printerStart = false;
} else {
endTime = System.currentTimeMillis();
Log.e(TAG,"current endTime: " + endTime);
printerStart = true;
}
}
网友评论