Android性能优化二 启动性能优化

1,394 阅读3分钟

Android启动

冷启动: 冷启动是指应用从头开始启动;系统进程在冷启动后才创建进程,调用Appcaliton.onCreate 热启动: 在热启动中,系统所有的工作就是将Activity带到前台。 不会调用Appcaliton.onCreate

冷启动耗时统计

系统日志统计

我们只优化冷启动的时间 如何查看启动时间 Android4.4以上可以在 Logcat中 输入ActivityTaskManager: Displayed查看。 会显示启动时间

adb命令方式 不需要root

adb shell am start -S -W [packagename]/[activity]

adb shell am start -S -W com.smzc.driver/.ui.activity.SplashActivity

冷启动

热启动

waitTime:包括前一个应用的Activity pasuse时间和新应用启动耗时 thisTime 表示一连串启动Activity的最后一个Activity的启动耗时 totalTime表示新应用启动耗时,包含新进程的启动和Activity的启动,但不包括前一个应用Activity pasuse 耗时

totalTime是到Activity的OnWindowFocusChanged(boolean hasForcus)

那么我们如何知道 在Appcalition.onCreate 方法到 Activity.OnWindowFocusChanged方法内是哪些方法耗时呢?

可以在AndroidStudio中选择这个 也可以在Appcalition的构造方法中

    public MyApplication() {
         @Override
    public void onCreate() {
        final File methodTracingFile = new File(getExternalFilesDir("trace"), "AppStart.trace");
        //在手机的SD卡文件创建了一个文件AppStart.trace       //要有文件写入权限
        Debug.startMethodTracing(methodTracingFile.getPath());
    }
    
    public class MainActivity extends AppCompatActivity {
    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        Debug.stopMethodTracing();
    }

然后点击Android studio profile 启动Activity 这个profile有些问题 华为和小米手机 会崩溃 出不来下面的效果 所以不是很好用

Flarm Chat

setContentView加载布局 耗时太多,可以用异步加载布局 在子线程 加载布局

new AsyncLayoutInflater(this).inflate(R.layout.activity_main, null,
         new AsyncLayoutInflater.OnInflateFinishedListener() {
              @Override
              public void onInflateFinished(@NonNull View view, int resid, @Nullable ViewGroup parent) {
                        setContentView(view);
              }
          });

严苛模式 不确定哪些方法在主线程是否耗时操作。 在debug开启StrictMode

Android 性能中体验的优化

黑白屏的问题 我们在启动的Activity添加上这个主题就会有黑白屏
所以android:windowBackground可以设置一张图片 这个就是Android启动的体验上的优化

启动优化

  1. 合理的使用异步初始化,延迟初始化,懒加载机制

  2. 启动过程避免耗时操作,如数据库I/O操作不要放到主线程执行

  3. 类加载优化:提前异步执行类加载。

  4. 合理使用idleHandler进行延迟初始化

  5. 简化布局

IdleHandler是一个回调接口,可以通过MessageQueue的addIdleHandler添加实现类。当MessageQueue中的任务暂时处理完了(没有新任务或者下一个任务延时在之后),这个时候会回调这个接口,返回false,那么就会移除它,返回true就会在下次message处理完了的时候继续回调。 返回true 多次执行 返回false 执行一次

实战体验App的优化

我们通过添加

Debug.startMethodTracing

方法后 查看布局时消耗资源,然后在启动的Activity的OnWindowFocusChanged方法中停止

Debug.stopMethodTracing()

1. 层级的优化!

通过LayoutInspector 查看布局

调试查看布局深度

2. 过度渲染

开启过度渲染

卡顿分析

Systrace的使用

Systrace systrace.py -t 10 -o d:/mytrace2.html wm gfx input view sched freq -a com.yisingle.simulation.trip.driver

App层面监控卡顿

1. 利用UI线程中Looper打印日志匹配;

Looper.class
	    public static void loop() {
                   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);
            }
        
        }

BlockCanaray的原理。

所以我们可以通过这个日志来获取间隔时间来获取代码的执行的时间

LogMonitor logMoitor=new LogMoitor()

Looper.getMainLooper().setMessageLogging(logMoitor)

实现下面的这个接口就可以

public interface Printer {
    /**
     * Write a line of text to the output.  There is no need to terminate
     * the given string with a newline.
     */
    void println(String x);
}

使用

2. Choreographer.FramCallBack;