启动速度与卡顿等方面的性能优化是一个比较复杂的多方位的优化,需要我们在项目中不断实践,不断的总结经验;本篇只是简要介绍相关的概念以及优化的工具和方向等;
其实启动速度、卡顿和布局等方面的优化都是环环相扣的,每个方面的优化都会或多或少的影响到其他方面。并且这些方面的优化其实是一些细枝末节的繁琐的操作,还需要我们对项目有很大程度的了解,并且优化了很多小方面之后可能效果并不显著,这是很正常的,我们不应该比较绝对时间,而是应该和项目的之前的时间进行比较,有没有细微的优化,这些细微的变化加在一起,也可能会有不小的影响;
一、启动速度优化
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分析器;
- run — edit Configurations — profiling — start this recording on startup前面打勾
- 主要有两种模式可以选择,sample java methods:间隔时间采样,每隔一定时间进行采样,分析相应方法的时间占用;trace java method:方法调用跟踪,会跟踪调用每个方法,然后记录每个方法的耗时,这种方式特别卡,并且也没有必要,一般使用第一种足以;
- 保存之后,我们以profile方式启动app,即可在profiler界面查看启动耗时相关信息;
- 在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分析器进行分析;
- 打开Profiler界面,保持应用运行在设备上或者模拟器上;
- 点击cpu运行模块进入cpu分析界面;
- 在Select CPU Profiling mode中选择Trace System Calls,并点击record;
- 然后在设备上操作我们应用想要分析的界面,操作完成后点击stop;
- 此时会自动生成SystemTraceRecording界面;
我们可以在生成的界面上进行分析,界面显示了许多有用的信息,比如每一帧的消耗时间,如果时间过长会变红,并且在下面时间条显示具体方法名;
我们还可以在右边的Top down界面查看具体方法调用栈信息;跟启动速度优化的右侧界面相同;
三、布局分析
布局方面的优化主要可以从三个方面进行分析;
1、层级优化
framework层在对布局进行measure、layout和draw操作时是一层一层布局递归调用的,因此我们的布局层次结构越深,则耗时越久,我们应该尽量减少布局层级,扁平化处理布局;
我们可以使用Android studio自带的Layout Inspector布局分析器进行布局的分析;
- 在设备或者模拟器上运行我们的应用;
- Tools — layoutinspector进入布局分析界面,系统会自动检测应用进程并展示;
- 在左侧视图树界面查看视图层级;右侧属性界面查看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);
//......
}
});
复制代码