APP的性能优化是永恒的主题,今天我们来详细梳理一下。
1.布局优化
APP的最主要的功能就是展示,布局就是最直观的展示效果,渲染布局的工作是复杂的。
布局的根部是一个ViewGroup组件,多个ViewGroup的嵌套,就使得View树变得更大,布局的层级也越来越深,最终影响我们应用的性能。
1.1 减少布局嵌套
我们常用的ViewGroup有三种:LineraLayout,FrameLayout,RelativeLayout,FrameLayout相对来说比较特殊,就不去讨论了。在LinearLayout和RelativeLayout的选择上我们要灵活考虑,在不涉及层级嵌套的前提下,我们尽可能使用LinearLayout,LinearLayout的测量会比Relative
Layout更加快速,因为RelativeLayout是相对布局,要考虑上下和左右方向的测量。
1.2 使用Google提供的标签
Google为我们提供了include,merge,ViewStub三种标签,下面我简单介绍一下用法。
include主要用于布局的重用。
merge主要用于减少层级嵌套。
ViewStub主要是实现一种按需加载。简单来说就是由代码控制布局的加载时机。
1.3 最新引入的布局—约束布局(ConstraintLayout)
约束布局是Google提供给我来减少布局嵌套的新布局,感觉起来和RelativeLayout差不多,但是ConstraintLayout更加强大,给大家一个ConstraintLayout用法介绍
2.绘制优化
这个优化主要是针对我们在自定义View的时候,布局和绘制是影响我们显示的两个因素,布局优化的提升效果可能不是那么明显,我们平时感觉到的卡顿还是绘制的问题,Android的绘制机制是每隔16ms发出信号,对UI进行渲染绘制,但是这期间有不少的未知因素的影响,严重的就会造成卡顿等问题,绘制的方法主要就是onDrae()了,所以:
- 我们在onDraw()的方法里面不要做耗时任务,这会极大的影响绘制的流畅度。
- 我们不要再onDraw()方法里面频繁的创建局部变量,因为onDraw()方法的调用频率很高,过多的局部变量会对性能照成损耗,最终会影响性能。
3.内存优化
在内存优化里面有一个不得不提的概念—内存泄漏,泄漏的意思就是,有一部分的内存我们不能再管理了,因为对象的引用被另外的对象持有,而且持有引用的对象的生命周期还比较长,造成了这块内存不能回收再利用。
集合造成的泄漏
集合类会持有集合内部对象的引用,我们应该在不使用的时候,进行集合的释放。
静态造成泄漏
静态的声明周期贯穿整个程序,非常容易造成内存的泄漏。在我们传递引用的时候,大部分会是Context对象,这时我们有两种方式来解决内存泄漏的问题:
- 使用全局的Context对象,就是Application对象,Application的生命周期也很长,不存在内存泄漏的问题。
- 使用弱引用或者软引用包裹Context对象,使用get()方法来调用包裹Context对象。
内部类造成内存泄漏
内部类会隐式的持有外部类的引用,而且内部类的生命周期可能比外部类时间更长,所有有很大可能造成内存泄漏。解决的办法就是声明称静态的内部类。
资源没有及时关闭造成
这个就主要靠我们平时自己注意了,比如I/O流,动态注册广播,Service调用stopSelf()方法(onStartCommand()执行完毕之后,再调用onDestroy())等。
关于内存优化有几个工具是比较常用的:leakcanary,Android Lint,Android Profiler。
4.启动优化
Android的启动一般分为3种方式,分别是:冷启动,暖启动,热启动。启动方式的不同,影响了APP可见时需要的时间,而冷启动才是我们最要关注的一种。
冷启动
每一个Android程序都需要进程来维持运行,当我们程序需要的进程还没有创建的时候,这时APP就会采用冷启动的方式,冷启动一般发生在APP第一次启动或者手动停止之后再次启动。
冷启动发生时,系统会做三个任务:
- 加载并启动应用
- 启动后显示应用程序的空白启动窗口
- 创建应用进程
进程创建好了之后,接着就开始创建应用程序对象:
- 初始化应用的对象(Application的初始化)
- 启动主线程
- 创建MainActivity
- 加载xml布局
- 计算布局再屏幕上的位置
- 绘制布局
第一次绘制完成之后,空白启动窗就会被Activity的内容替换掉,这个时候我们才可以和用户进行交互了。
暖启动
暖启动包含了冷启动的一些操作,但是它的开销上更节省,一般在应用退出与重启时,会发生暖启动。
热启动
热启动的速度上是最快的,如果activity还在内存当中,它不需要初始化和布局加载、绘制的过程。在热启动的时候,系统也会显示一个空白的屏幕,直到Activity处于可见的状态。
通过上面的了解,我们知道了优化的重点在于,Application和MainActivity的onCreate()的方法里面,我们要尽可能的减少耗时操作:
- 异步加载与主业务关联较少的框架。
- 非第一时间使用的功能可以采用延时加载。
谷歌官方建议我们:
- 利用开始的空白的window,展示出一个界面,给用户一个快速的反馈。
- 避免在启动的时候,做出密集的初始化。
利用空白window
我们可以利用主题中的android:windowBackground属性,可以给window设置一个背景,用于初始化的时候进行展示。
<style name="StartAppTheme" parent="AppTheme">
<item name="android:windowBackground">@drawable/start_app_bg</item>
</style>
再在AndroidManifest.xml文件里面设置主题
<activity
android:name=".MainActivity"
android:theme="@style/StartAppTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
然后我们在MainActivty的onCreate()的设置为正常主题
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//把主题改成正常状态
setTheme(R.style.AppTheme);
setContentView(R.layout.activity_main);
以上。