Android开发性能优化
很多时候,我们只注重功能的实现,很少去注重性能的开发。产品商务逼的嘛,哈哈。
性能优化,目的是啥呢?
- 省电
- 运行流畅、快速
- 稳定
- apk包体积小
布局优化
布局优化则是减少CPU的执行时间,不仅省电,渲染速度也快。
布局优化方面,减少嵌套。
所以问题是如何减少嵌套呢?
- 同样的布局有多种写法,所以编写布局的时候思想上,意识上就要想着减少布局
- 能使用LainerLayout或者FrameLayout的就不要使用RelativeLayout,RelativeLayout绘制比较复杂一些
- 结合include和merge使用,减少布局层次
- 使用ViewStub来加载一些不一定要显示的View,比如说状态的View,网络错误,内容为空
- Google推荐使用ConstraintLayout来编写布局,减少布局嵌套
View的绘制优化
关于View的绘制,主要是在我们自定义控件的时候要考虑。优化绘制,可以让用户体验流程,节省内存,节省电量。
-
不要在onDraw方法中创建对象
在onDraw方法里头,不要创建对象。因为onDraw方法是频繁调用的,如果在onDraw方法里创建对象,则会频繁创建对象。此对象在栈中使用完就释放了,于是就要等待GC回收。如果内存不够用,则会频繁上回收,加之频繁创建则使内存在一个波动的状态,一旦超出了限制范围,则会出现内存溢出。
-
不要在onDraw方法中做耗时操作
onDraw方法是在主线程中调用的,如果在onDraw方法中有耗时操作,容易造成ANR异常。所以呢,要避免在onDraw方法中执行耗时操作。
如何防止内存泄露
内存泄露是什么呢?在JVM进行垃圾回收时,如果对象还被引用,则不会回收的。也就是说一些不使用的对象,但是还被其他地方持有引用,无法回收,这就是内存泄露。
内存溢出又是啥?内存溢出就是碗溢出,一个碗只能装这么些水了,超出了范围则会溢出。内存也一样,超出了容量就会溢出。大量的内存泄露,导致内存无法回收可能会引起内存溢出。
那么减少或者避免内存溢出,可以提高稳定性,所以这个也是我们的优化项之一。
原则:创建-释放,生命周期:短的可以持有短的,短的可以持有长的。短的释放得快,所以不影响声明周期长的释放。
单例
单例需要使用到context,刚学android的同学可能就直接把Activity传进去了。
如果这个Activity的生命周期完事了,但是它还被单例所持有,那么就无法回收了。
遵循生命周期长的可以持有生命周期长的原则,此种单例可以持有application的Context
内部类
内部类有:静态内部类、非静态内部类(匿名内部类)
- 静态内部类的生命周期独立,如果没有外部类的传参,不持有外部类的引用。
- 非静态内部类持有外部类的引用
以上原则,就可以知道如果我们一个内部类在做耗时操作,生命周期比外部类长的话,那么就可能造成内存泄露了。
那么匿名内部类如何解决呢?
最常见的是我们的Handler,经常以匿名内部类的形式new出来
如果消息处理里有生命周期比较长的操作,比如说postDelay一个长时间的值
那么就有可能导致内存泄露了
已经提示可能会内存泄露了
那怎么处理 呢?
我们可以把handler改成静态的内部类
kotlin里没有加inner是嵌套类,不会持有外部类的引用,但使用不了外部类的参数,如果内部类需要调用外部类的参数,则可以添加inner,inner为内部类,会持有外部类的引用。
class InnerHandler(activity: AppCompatActivity) : Handler() {
private var wActivity: WeakReference<Activity> = WeakReference(activity)
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
if (wActivity.get() != null) {
return
}
//TODO:
}
}
Java则可以改成静态的内部类,静态内部类不持有外部类的引用,如果要使用外部类的成员,可以通过传参持有外部类引用,通过软引用的方式持有。
其他补充
- 集合使用完要清空,置空
- 广播注册了,不需要的时候要取消注册
- 各种回调方法,通过add方式添加的,不使用的时候要记得删除
- IO网络这些得关闭,通常开发的时候,可以使用优秀的框架完成
- ....
应用启动优化
应用启动也是一个很重要的优化,直接影像用户的体验。
主要优化项
- 首屏渲染
- application的onCreate方法各种初始化项
- activity的onCreate方法执行内容
轻量级的欢迎屏
如果打开一个应用是冷启动,那么很有可能出现白屏/黑屏的现象。推荐使用一个轻量级的欢迎页,里面做一个logo之类的。
比如说:
<style name="WelcomePageThem" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="android:windowBackground">@mipmap/welcome_page_bg</item>
<item name="android:windowFullscreen">true</item>
</style>
在欢迎页使用此主题
Application的onCreate方法各种初始化项
对于各种初始化,应该遵循以下原则:
- 不是必须马上初始化的可以推迟初始化
- 不是必须在主线程上初始化的可以异步初始化
- 必须在主线程初始化的先初始化
Activity的onCreate方法
在Activity的onCreate方法里,我们通常会初始化布局和相关的事件,但是不要做耗时操作。加载数据之类的异步开启。这里面也可以通过前面提到的优化布局去提升速度。
数据加载则异步加载,如果可以做缓存则缓存
应用体积优化
对于应用体积来说,我们开发的时候可能没有在意。减小应用体积有什么好处呢?
- 加快用户下载的速度,体验上会好点
- 节省带宽和用户流量,如果你是做系统的,ota升级可以省不少钱呢
指导方向:
-
代码
-
混淆,取出没用上的代码
-
除去/合并同样功能的第三方库
-
可以使用Lint检查一下代码质量
Analyze -> Run Inspection by Name -> unused declaration -> Moudule ‘app’ -> OK
-
-
资源
主要是图片优化。能使用矢量图的就使用矢量图,不能矢量图的使用WebP,不能WebP的使用png,不能png的就jpeg.
工具:
Android Size Analyzer AndroidStudio插件
电池优化
电池优化也算是性能里的一块,优化项也比较泛,有点从细节做起的样子。
相关文章
电池优化的工具:
使用 Batterystats 和 Battery Historian 分析电池用量
优化项
- 传感器、GPS这些是耗电大户,如果要使用短暂使用,间隔使用,使用完要关闭
- 移动网络比WI-FI耗电量大,如果有大数据要上传或者下载,可以在WI-FI环境下进行上传/下载,比如说系统升级的OTA包。
- 如果非必须马上要执行的工作,可以放在用户充电的时候去完成,可以借助Jobscheduler