android进阶篇08、启动速度、卡顿与布局优化简述

2,233 阅读6分钟

启动速度与卡顿等方面的性能优化是一个比较复杂的多方位的优化,需要我们在项目中不断实践,不断的总结经验;本篇只是简要介绍相关的概念以及优化的工具和方向等;

其实启动速度、卡顿和布局等方面的优化都是环环相扣的,每个方面的优化都会或多或少的影响到其他方面。并且这些方面的优化其实是一些细枝末节的繁琐的操作,还需要我们对项目有很大程度的了解,并且优化了很多小方面之后可能效果并不显著,这是很正常的,我们不应该比较绝对时间,而是应该和项目的之前的时间进行比较,有没有细微的优化,这些细微的变化加在一起,也可能会有不小的影响;

一、启动速度优化

1、启动状态

冷启动:冷启动是指应用进程不存在,需要先启动应用进程,然后再启动activity;

温启动:温启动是指我们退出应用,然后再重新打开应用,此时如果应用进程没被杀死,就不需要重新启动进程,只需要启动activity就行;

热启动:热启动是指应用被切到后台,进程和activity都还在内存中没被杀死,直接由后台切换到前台即可,不需要重新启动进程和activity;

2、启动耗时统计

方法一

第一种方法我们可以通过在Android Studio中的logcat日志界面查看,输入搜索关键字displayed,然后过滤条件选择No Filters,我们在启动应用时就会打印如下所示日志,代表启动耗时887毫秒;

2021-03-27 15:55:56.648 524-551/system_process I/ActivityTaskManager: Displayed com.xiangxue.arch_demo/.MainActivity: +887ms

方法二

第二种方法我们可以在cmd命令行中通过命令查看,如下命令;

adb shell am start -S -W [packageName]/[activityName]

输出结果如下所示,其中TotalTime就是耗时时间;

C:\Users\29155>adb shell am start -S -W com.xiangxue.arch_demo/.MainActivity
Stopping: com.xiangxue.arch_demo
Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.xiangxue.arch_demo/.MainActivity }
Status: ok
LaunchState: COLD
Activity: com.xiangxue.arch_demo/.MainActivity
TotalTime: 887
WaitTime: 890
Complete

3、启动速度分析

分析启动速度我们可以使用Android studio自带的profiler分析器;

  1. run -- edit Configurations -- profiling -- start this recording on startup前面打勾
  2. 主要有两种模式可以选择,sample java methods:间隔时间采样,每隔一定时间进行采样,分析相应方法的时间占用;trace java method:方法调用跟踪,会跟踪调用每个方法,然后记录每个方法的耗时,这种方式特别卡,并且也没有必要,一般使用第一种足以;
  3. 保存之后,我们以profile方式启动app,即可在profiler界面查看启动耗时相关信息;
  4. 在prfiler界面主要看三个模块来分析启动耗时 Top Down:方法的调用栈信息,我们可以通过分析方法调用栈过程中的各个方法的耗时时间,来确定是在那个过程中耗时较多; Flame Chat:又称火焰图,是以时间条的形式对方法的耗时进行记录,我们一般在这个图上总览一下各个方法的耗时,真正去分析时间还得去Top down中分析具体的方法; Bottom Up:也是方法的调用信息,不过跟Top Down正好相反,是从底部往顶部查找的,一般不看这个模块,查找不方便,看第一个方法调用栈就可以;

4、黑白屏问题

当我们点击app图标时,在应用还没有启动起来的时候会有白屏或者黑屏代替,这是google提供的界面加载方法,不过用户体验不好,我们可以通过设置背景图的方法解决;

我们首先定义style属性,将windowbackground属性设置为我们的背景图片;

然后在activity标签中修改theme属性,使用我们自定义的style标签;

最后我们要在activity的oncreate方法中settheme设置回应用的主题,因为启动了之后还是需要使用应用的主题的;

添加背景图片并不能对启动速度有优化,只是为了提高用户体验度;

<resources>
    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="windowNoTitle">true</item>
        <item name="windowActionBar">false</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

    <style name="AppTheme.myapp">
        <item name="android:windowBackground">@drawable/ic_controls</item>
    </style>
    
</resources>

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:name=".application.ArchDemoApplication"
    android:theme="@style/AppTheme">
    <activity
        android:name=".MainActivity"
        android:theme="@style/AppTheme.myapp">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

protected void onCreate(Bundle savedInstanceState) {
    setTheme(R.style.AppTheme);
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    、、、
}

二、卡顿分析

卡顿分析跟启动速度的分析的操作基本相同,也是使用Android studio自带的profiler分析器进行分析;

  1. 打开Profiler界面,保持应用运行在设备上或者模拟器上;
  2. 点击cpu运行模块进入cpu分析界面;
  3. 在Select CPU Profiling mode中选择Trace System Calls,并点击record;
  4. 然后在设备上操作我们应用想要分析的界面,操作完成后点击stop;
  5. 此时会自动生成SystemTraceRecording界面;

我们可以在生成的界面上进行分析,界面显示了许多有用的信息,比如每一帧的消耗时间,如果时间过长会变红,并且在下面时间条显示具体方法名;

我们还可以在右边的Top down界面查看具体方法调用栈信息;跟启动速度优化的右侧界面相同;

三、布局分析

布局方面的优化主要可以从三个方面进行分析;

1、层级优化

framework层在对布局进行measure、layout和draw操作时是一层一层布局递归调用的,因此我们的布局层次结构越深,则耗时越久,我们应该尽量减少布局层级,扁平化处理布局;

我们可以使用Android studio自带的Layout Inspector布局分析器进行布局的分析;

  1. 在设备或者模拟器上运行我们的应用;
  2. Tools -- layoutinspector进入布局分析界面,系统会自动检测应用进程并展示;
  3. 在左侧视图树界面查看视图层级;右侧属性界面查看view属性;

使用merge标签

有一些布局需要在多处使用时,我们可以将其抽离成一个单独的布局文件,然后在需要的地方直接include即可,此类布局就可以使用merge标签,这个布局在附加到别的布局中时,merge标签会自动删除掉,如果不使用merge标签,而是使用布局标签包裹,那么就会产生一层冗余的布局嵌套;

使用ViewStub标签

当布局中某个view或者viewgroup在特殊情况下才会显示时,我们可以使用viewstub标签,它不可见不占用资源,只有当我们设置为visible或者调用inflater方法时才会被初始化;

2、过度渲染

我们可以通过开启开发者模式的渲染选项查看是否存在过度绘制; 过度绘制一般采用考虑通过如下方式解决;

  • 移除掉布局中不需要的背景
  • 尽量使视图层级结构扁平化

3、布局加载优化

异步加载 可以通过使用androidX中的库进行布局的异步加载

implementation "androidx.asynclayoutinflater:asynclayoutinflater:1.0.0"

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); 
			//...... 
		} 
	});