Android性能优化

学习了解要点

  • 布局优化
  • 内存优化
  • 使用各种工具来进行分析,优化

一 布局优化

系统在渲染UI界面的时候将消耗大量的资源,一个好的UI不仅应该有良好的视觉效果,更应有良好的使用体验,因此布局优化就显得非常重要。

1.1Android UI渲染机制

人眼所感觉的流畅画面,需要的帧数达到40帧每秒到60帧每秒,PC游戏最佳fps在60fps左右,这是评价显卡性能高低的标准之一。

在Android中,系统通过VSYNC信号触发对UI的渲染,重绘,其时间间隔是16ms。这个16ms其实就是1000ms中显示60帧画面的单位时间,即1000/60.如果系统每次渲染的时间都保持在16ms之内。如果不能在16ms内完成绘制,那么就会造成丢帧现象,即当前该重绘的帧被未完成的逻辑阻塞。
例如一次绘制任务耗时20ms,那么在16ms系统发出VSYNC信号时就无法绘制,该帧就被丢弃,等待下次信号才开始绘制,导致16*2ms内都显示同一帧画面,这就是画面卡顿的原因

1.2避免Overdraw
Overdraw,过度绘制会浪费很多的CPU,GPU资源,例如系统默认会绘制Activity的背景,而如果再给布局绘制了重叠的背景,那么Activity的背景就属于无效的过度绘制—Overdraw。Android系统在开发者选项中提供了一个检测工具——“Enable GPU Overdraw”。激活后可以通过界面上的颜色判断Overdraw的次数。
开发者通过这个工具可以查看绘制次数,从而尽量优化绘图层次,尽量增大蓝色区域,减少红色区域。

1.3优化布局层级

在Android中,系统对View进行测量,布局,绘制时,都是,通过对View树的遍历来进行操作的。如果一个View树高度太高,就会严重影响测量,布局和绘制的速度,因此优化布局的第一个方法就是降低View树的高度,Google也在其API文档中建议View树的高度不宜超过10层。

1.4避免嵌套过多的无用布局

嵌套布局会让View树变高,布局时应避免这情况

1.4.1使用< include>标签重用Layout

原模板组件width和height设为0,用的时候使用< include>,在这个标签里重新设置width和height。

1.4.2使用< ViewStub>实现View的延迟加载

< ViewStub>是一个轻量级的组件,它不仅不可视,而且大小为0.

两种方法重新显示这个在布局中使用ViewStuv包裹的View
先findViewById找到这个组件

  1. 方法一 ——调用它的VISIBLE方法
  2. 方法二 ——调用ViewStub的inflate()方法——这种方法可以返回引用的布局,从而通过这个引用的布局调用findViewById来找到这个布局里面对应的控件。

不管哪种方式展开ViewStub一旦被设置为可见或是被Inflate了,< ViewStub>就不存在了,取而代之的是被Inflate的Layout,并将这个LayoutID重新设置为< ViewStub>中通过android:inflatedId属性所设定的Id,也因此如果调用两次Inflate方法会报错.
ViewStub只有在显示时才会去渲染整个布局,而View.GONE,在初始化的时候就已经添加在布局树上了,相比之下,ViewStub标签都得布局具有更高的效率。

1.5Hierarchy Viewer

Hierarchy Viewer无法在真机上使用,只能在工厂的Demo机和模拟机上使用,即非加密过的设备
开源项目View Server可以让普通手机也能使用Hierarchy Viewer
https://github.com/romainguy/ViewServer

Hierarchy位于sdk\toos目录下,在命令行输入hierarchyviewer.bat启动程序

个人在网上随便看了篇布局优化工具Hierarchy Viewer

二:内存优化

2.1什么是内存

由于Android应用的沙箱机制,每个应用所分配的内存大小是有限度的,内存太低就会触发LMK——Low Memory Killer机制。通常情况下我们所说的内存是手机的RAM,它包括以下几个部分。

  • 寄存器(Registers)——速度最快的存储场所,因为寄存器位于处理器内部,在程序中无法控制。
  • 栈(Stack)——存放基本类型的数据和对象的引用,但对象本身不放在栈中,而是存放在堆中。
  • 堆内存用来存放new创建的对象和数组。在堆中分配的内存,由Java虚拟机的自动垃圾回收器(GC)来管理。
  • 静态存储区域(Static Field)——静态存储区域就是指在固定的位置存放应用程序运行时一直存在的数据,Java在内存中专门划分了一个静态存储区域用来管理一些特殊的数据变量如静态的数据变量。
  • 常量池(Constant Pool)JVM必须为每个被卸载的类型维护一个常量池。常量池就是该类型所用到的所有常量的一个有序集和,包括直接常量(基本类型,String)和对其他类型,字段和方法的符号引用。

堆和栈的区分最容易搞错。
当定义一个变量,Java虚拟机就会在栈中为该变量分配内存空间,当该变量作用域结束后,这部分内存空间会马上被用作新的空间进行分配。如果使用new的方式创建一个变量,那么就会在堆中为这个变量分配内存空间,即使该对象的作用域结束,这部分内存也不会立即被回收,而是等待系统GC进行回收。堆的大小随着手机的不断发展二不断变大。在程序中可以使用以下代码来获取堆的大小,所谓内存分析,正是分析Heap中的内存状态。

 ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        int heapSize = manager.getLargeMemoryClass();

2.2获取系统内存信息
2.2.1Process Stats是KK上新增的一个系统内存监视服务,可以通过“Setting_Developer options-Process Stats”来开启该功能的界面。

adb shell dumpsys procstats

Android性能优化_第1张图片
2.2.2 Meminfo

Meminfo也是系统上的一个重要的内存监视工具,可以在Settings-Apps Running中打开这一界面
同样也可以使用Dumpsys命令

`adb shell dumpsys meminfo
Android性能优化_第2张图片
2.3内存回收
Java对于C,C++这类语言最大的优势就是不用手动管理内存资源,Java创建了垃圾收集器线程来自动进行资源的管理。大大降低了程序开发人员对内存管理的繁琐工作。
但是——Java GC是自动进行的,开发者无法控制,即使调用System.gc()方法,也只是建议系统进行GC,但系统是否采纳你的建议,说不准。JVM虽然能够自动控制GC,但是再强大的算法,也难免会存在纰漏,这就是造成内存泄漏的原因——由部分对象忘记回收。

2.4内存优化实例

1.Bitmap优化
Bitmap是造成内存占用过高甚至是OOM的最大威胁。下面是一些使用Bitmap的小技巧。

  • 使用适当分辨率和大小的图片——如果图片分辨率与资源文件夹分辨率不匹配或者图片分辨率太高,就会导致消耗更多的内存资源。
  • 即时回收内存——一旦Bitmap使用完后,一定要即时使用bitmap.recycle()方法释放内存资源。自Android3.0后,Bitmap放置到了堆中,内存由GC管理,不需要进行释放了。
  • 使用图片缓存——内存缓存和硬盘缓存可以更好地使用Bitmap。

2.4.2代码优化

  • 对常量使用static修饰符
  • 使用静态方法,静态方法会比普通方法提高15%左右访问速度
  • 减少不必要的成员变量,这点再Android Lint工具上已经集成检测了,如果一个变量可以定义为局部变量,则会建议你不雅定义成员变量
  • 减少不必要的对象,使用基础类型会比使用对象更加节省资源,同时更应该避免频繁创建短作用域的变量。
  • 尽量不适用枚举,少用迭代器
  • 对Cursor,Receiver,Sensor,File等对象,要非常注意它们的创建,回收与注册,解注册。
  • 避免使用IOC框架,IOC框架通常使用注解,反射来进行,虽然现在Java反射的效率已经进行了很好的优化,但大量使用反射依然会带来性能的下降。
  • 使用RenderScript,OpenGL来进行非常复杂的绘图操作。
  • 使用SurfaceView来代替View进行大量,频繁的绘图操作
  • 尽量使用视图缓存,而不是每次都执行inflate()方法解析视图。

三:Lint工具

Android Lint工具是AS中集成的一个Android代码提示工具,它可以给你的布局,代码提供强大的帮助。如果写了冗余的XML视图代码,编辑器会给予警告。还有很多强大的功能。

四:AS的Memory Monitor工具

Memory Monitor是AS自带的一个内存监视工具,它可以很好地帮助我们进行内存实时分析

五 TraceView工具优化App性能

5.1生成TraceView日志的两种方法

一种是利用Debug类帮助我们生成日志文件,另一个是利用Android Device Monitor工具辅助生成日志文件。

5.11通过代码生成精确范围的TrceView日志

利用Debug类的方法开启TraceView监听。通过调用Debug.startMethodTracing()方法开启监听,通过调用Debug.stopMethodTracing()方法结束监听,我们可以使用这两个方法来包围要监听的代码块。
例如在onCreate()方法里调用startMethodTracing()方法来开启监听,在onDestroy()方法里使用stopMethodTracing()方法来结束监听。TraceView日志将会保存到“/sdcard/dmtrace.trace”目录下,因此需要在Mainifest文件中增加如下所示的权限。

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

当然,也可以自定义输出日志名,路径。
要监听的内容执行完毕后,通过ADB命令将日志文件导出到本地,命令如下

adb pull /sdcard/trace_log.trace/local/LOG

5.1.2通过Android Device Monitor生成TraceView日志
Incl CPU Time —— 某方法占用CPU的时间
Excl CPU Time —— 某方法本身(不包括子方法)占用CPU的时间
Call + RecurCalls —— 调用次数+递归回调的次数

Android性能优化_第3张图片
每个时间包含两列,一个是实际时间,另一个是百分比。分析的时候通常从Incl CPU Time 和 Calls+RecurCalls开始分析,对占用时间长的方法重点分析,如果占用时间长,且Calls+RecurCalls少,那就是重点怀疑对象。

六 使用MAT工具分析App内存状态

MAT分析内存
Android性能优化_第4张图片
小技巧 当我们不停地点击“Cause GC”按钮时,如果“data object”一栏中的"Total Size"有明显变化,就代表可能存在内存泄漏

上面是手动查看Heap状态,下面点击“Dump HPROF File”系统会生成.hprof文件。

个人看到这里发现郭神和刘望舒写的性能优化文章不错,链接:郭 ——链接:刘。

七:使用Dumpsys命令分析系统状态

使用Dumpsys命令可以列出Android系统相关得信息和服务状态。Dumpsys得官方信息可以从如下网址获取
https://developer.android.com/studio/command-line/dumpsys

使用Dumpsys命令时,只需要输入“adb shell dumpsys+参数”,例如

adb shell dupsys activity

常用dumpsys命令

  • activity——显示所有得Activity栈得信息
  • meminfo——内存信息
  • battery——电池信息
  • package——包信息
  • wifi——显示WI-FI信息
  • alarm——显示alarm信息
  • procstats——显示内存信息

配合Linux下得shell命令,可以发挥dumpsys更加强大得作用。

你可能感兴趣的:(群英传读书笔记)