Android卡顿检查

一:常见方案

1 通过UI 线程looper

2 通过Choreographer

1.1 通过UI 线程looper的打印日志

在github上也有许多开源库是基于该原理,比较有代表行的有

AndroidPerformanceMonitor

通过如下代码可以看到,只存在一个主线程的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;
        }
    }

你可能感兴趣的:(Android卡顿检查)