Android 开发小技巧备忘【调试】

| 分类 Android  | 标签 技巧 

1、动态dump

1) Native C++版本

#include <utils/CallStack.h>然后使用CallStack类

2) Java版本

Exception e = new Exception("dumpinfo");  
e.printStackTrace()
//或者
Log.w("tag", Log.getStackTraceString(new Exception()))


2、卡顿

1) adb shell dumpsys

adb shell dumpsys SurfaceFlinger
adb shell dumpsys gfxinfo 

2) 利用UI线程的Looper打印的日志

Looper.loop()中,dispatchMessage前后会打印日志
Looper.getMainLooper().setMessageLogging(new Printer())
打印UI线程的堆栈信息
  StringBuilder sb = new StringBuilder();
  StackTraceElement[] stackTrace = Looper.getMainLooper().getThread().getStackTrace();
  for (StackTraceElement s : stackTrace) {
      sb.append(s.toString() + "\n");
  }
  Log.e("TAG", sb.toString());
可以在日志打印前后,也就是监控加入和移除之间,进行高频的采集堆栈信息。
一般来说,一个卡顿是否发生的耗时阈值是80ms(5*16.6ms),
当一个卡顿达80ms的耗时,采集1~2个堆栈基本可以定位到耗时的堆栈。
采样堆栈的频率我们设为52ms(经验值)。
高频采样会带来海量的堆栈数据,通常卡顿点dump出的都是一样的堆栈;
可以做hash处理,排重去重减少数据量。

3) 利用Choreographer.FrameCallback监控卡顿

Choreographer.getInstance().postFrameCallback(new Choreographer.FrameCallback())
Android系统每隔16ms发出VSYNC信号,来通知界面进行重绘、渲染,
每一次同步的周期为16.6ms,代表一帧的刷新频率。
当每一帧被渲染时会触发回调FrameCallback,
FrameCallback回调doFrame(long frameTimeNanos)函数。


3、反射

1) 反射获取类的成员变量

onPause的时候,在每一帧打印出主线程消息队列中的所有消息 
private Field messagesField;
private Field nextField;
{
    try {
        messagesField = MessageQueue.class.getDeclaredField("mMessages");
        messagesField.setAccessible(true);
        nextField = Message.class.getDeclaredField("next");
        nextField.setAccessible(true);
    } catch (NoSuchFieldException e) {
        e.printStackTrace();
    }
}
@Override
protected void onPause() {        
    Choreographer.getInstance().postFrameCallback(new Choreographer.FrameCallback() {
            @Override
            public void doFrame(long frameTimeNanos) {
                Choreographer.getInstance().postFrameCallback(this);
                Log.d(TAG, "doFrame");
                printMessages();
            }
        });
    }
}
private void printMessages() {
    MessageQueue queue = Looper.myQueue();
    try {
        Message msg = (Message) messagesField.get(queue);
        StringBuilder sb = new StringBuilder();
        while (msg != null) {
            sb.append(msg.toString());
            sb.append("\n");
            msg = (Message) nextField.get(msg);
        }
        Log.i(TAG, sb.toString());
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }
}



上一篇     下一篇