《Android性能调优&优良程序风格》

版权声明:本文为博主原创文章,欢迎转载,转载注明出处即可~~ https://blog.csdn.net/WuchangI/article/details/82533185

Preface:

       运行Android系统的手机或其他移动设备,其内存和CPU性能都受到了一定的限制,这方面完全不能和PC机、服务器相比。所以,在开发App时,稍不留意,就会出现各种各样的不良情况。如果你的Android程序过多使用内存(导致OOM)、过多使用CPU资源(导致ANR)、内存泄漏(提高了OOM的发生几率)等,则会使得开发出来的App无法正常使用。所以,对于程序的性能调优至关重要。


       下面总结了常用的几种性能调优方法:

一、Android的性能调优方法

1. 布局优化

1.1基本思想

尽量减少布局文件的层级。

1.2 基本方法
  • 先检查一下当前的xml布局文件中是否有无用或多余的控件和层级,有则删除。
  • 有选择性地使用性能较低的ViewGroup(如RelativeLayout)。如果当前布局既可使用LinearLayout,也可使用RelativeLayout,则使用前者。LinearLayout和FrameLayout都是简单高效的ViewGroup,故布局时应多多考虑它们。
  • 如果实在有必要进行布局的嵌套,则直接使用RelativeLayout。
1.3 借助相关标签进行优化
  • <include>标签

它可以将一个指定的布局文件加载到当前的布局文件中,以实现布局文件的重用。

  • <merge>标签

它可以删减多余的层级,优化UI。多用于替换FrameLayout或当一个布局包含(include)另一个时,用它来消除层次结构中多余的ViewGroup。因此其经常和<include>标签配合使用。

  • <ViewStub>标签

它继承自View,是一个不可见的View,非常轻量级且宽和高均为0,因此其本身不参与任何的布局和界面绘制过程。它主要是提供了按需加载的功能,以实现对某些布局(比如进度条、网络异常界面等在特殊情况下才会显示的布局)的按需加载,减少内存的使用量并加快渲染速度。当要加载ViewStub中的布局时,可以借助setVisibility()方法或inflate()方法,此时ViewStub就会被其内部的布局替换掉。


2. 绘制优化

2.1 基本思想

要避免在View的onDraw方法中执行大量/耗时的操作。

2.2 基本方法
  • 在onDraw方法中不要创建新的局部对象

因为onDraw方法可能会被频繁调用,这将导致一瞬间产生大量的临时对象,占用过多内存且使系统更加频繁GC,降低了程序的执行效率。

  • 在onDraw方法中不要做耗时的操作

根据Android官方文档,View的绘制帧率保持在60fps是最佳的,也就是绘制每帧的时间大约为16ms。所以,我们应该尽量降低onDraw方法的复杂度,以提高绘制效率。


3. 内存泄漏优化

3.1 基本方法
  • 避免在开发过程中写出有内存泄漏的代码。
  • 通过一些内存泄漏分析工具来找出潜在的内存泄漏,继而加以解决。比如Eclipse的MAT、AS的Android Monitor(低于Android Studio3.0)和Android Profiler(Android Studio3.0以上)。
3.2 常见内存泄漏情况
  • 静态变量导致的内存泄漏

比如Activity中的类静态变量持有一个对该Activity实例的引用,这将导致该Activity实例无法释放。

(因为类静态变量在类被加载进JVM中时进入了方法区,只有在类被卸载的时候才能被销毁。而一般情况下,“类被卸载”发生在“进程结束”时。但是,若当前系统的资源足够,Android是不会杀掉任何进程的)

  • 单例模式导致的内存泄漏

比如Activity实例被单例模式中的某个对象持有,而单例模式的特点是其生命周期和Application保持一致,所以也导致了Activity实例无法被及时释放。

  • 属性动画导致的内存泄漏

Android的属性动画中有一类无限循环的动画,如果在Activity中播放此类动画且没有在onDestroy中去停止动画,则动画会一直播放下去,尽管已经在当前界面不可见了。这时,无限循环动画持有着对当前界面View的引用,而View又持有着对当前Activity的引用,最终导致Activity实例无法释放。

(解决的方法:在Activity的onDestroy方法中使用animator.cancel()方法来停止动画。)


4. 响应速度优化

4.1 基本思想

避免在主线程/UI线程中做耗时操作。

4.2 基本方法

借助多线程技术或线程池技术,将耗时操作放在子线程中执行,也就是采用异步的方式执行耗时操作。


5. ANR异常分析

5.1 常见原因及表现

主要原因是程序的响应速度过慢(主要体现在Activity的启动速度)。若在主线程中做了很耗时的操作,会导致启动Activity时出现黑屏现象,甚至是ANR。Android规定,Activity如果5秒钟之内无法响应屏幕触摸事件或者键盘输入事件,则会出现ANR。并且对于BroadcastReceiver,如果在10秒钟之内还未执行完操作也会出现ANR。

5.2 分析并找出根源

在实际开发过程中一旦出现了ANR,其在代码上是很难被发现的,要定位其根源需要一些手段。其实,一个进程发生ANR后,系统会在/data/anr目录下创建一个文件traces.txt,通过分析该文件即可定位出ANR的根源所在。


6. ListView优化

  • 基本方法:
    • 采用ViewHolder并避免在getView方法中执行耗时操作;
    • 要根据列表的滑动状态来控制任务(特别是异步任务)的执行频率;
    • 可以尝试开启硬件加速来提高ListView的滑动流畅度。


7. Bitmap优化

  • 基本方法:

通过BitmapFactory.Options根据需要对图片进行采样,采样过程中主要使用到了BitmapFactory.Options的inSampleSize参数。


8. 线程优化

  • 基本方法:

采用线程池,避免程序中存留大量的Thread,有效控制线程池的最大并发数。


9. 其他调优技巧

  • 避免创建过多的对象;
  • 不要过多使用枚举,因为枚举占用的内存空间比整型大;
  • 对于常量,加上static final修饰;
  • 考虑使用Android特有的一些数据结构,比如SparseArray和Pair等,它们都具有很好的性能;
  • 适当使用软引用和弱引用;
  • 采用内存缓存和磁盘缓存;
  • 尽量采用静态内部类,这样可以避免潜在的由于内部类而导致的内存泄漏问题。



二、Android的优良程序风格

优良的程序风格,无非就是指代码的可读性、层次性、扩展性等,以及设计模式的灵活运用。

1. 程序的可读性

  • 命名要规范

命名要正确传达出变量或方法的含义,少用缩写。变量的前缀书写格式可以参照Android源码的前缀命名方式。如私有成员以m开头,静态成员以s开头,常量则全部用大写字母表示等。

  • 代码排版合理

代码的排版上要留出合理的空白来区分不同的代码块,其中同类变量的声明要放在一组,两类变量之间要留出一行空白用以区分。

  • 注释适当

只为关键的代码添加注释,不添加不必要的注释。其实,这是对上面的命名规范提出了更高的要求,如果你的命名风格足够好,则可以使得阅读你的源代码的人觉得好像在阅读注释一样,此时根本不需要为代码添加注释,因为此源代码的命名就是最好的注释!


2. 程序的层次性

代码要有分层的概念,对于一段业务逻辑,不要试图通过一个方法或一个类去全部实现,而应考虑将其分成几个子逻辑,每个子逻辑做自己的事情(此时可以分别实现各个子逻辑),最终达到分解任务从而简化逻辑的效果。


3. 程序的扩展性

项目开发过程中,我们必须应对需求的未来变更的可能性,所以在编写程序过程中必须时刻考虑程序的扩展性,时刻保持着面向扩展编程。


4. 设计模式的融入

在程序中适当地融入设计模式,可以提高代码的可读性、可维护性、可扩展性,但Android程序比较特殊,它具有性能瓶颈,应控制应用设计模式的度,不能过度设计。









参考资料:《Android开发艺术探索》

猜你喜欢

转载自blog.csdn.net/WuchangI/article/details/82533185