App性能优化浅谈

前言

前段时间给公司的小伙伴们进行了关于app性能优化的技术分享。这里我稍微整理一下也给你们分享一下。关于性能优化这个话题很是大,涉及面可以很是广,也可以很是深刻。本人能力有限,不会给你们讲特别难懂,特别底层的东西。都是咱们开发能着手去作的点。你们都在讲性能优化,但对于项目经验不够丰富的朋友很是难有一个概念。作优化的时候也会比較茫然,这里我就给你们指明方向。数据库

从何讲起?

笔者在作产品开发的时候,也遇到性能瓶颈。測试project师反馈了一些比較明显的问题,比方UI界面的过分绘制,列表滑动有明显卡顿,比較耗内存等等,但以往的都没有针对性的去作对应的优化,因此借着保证产品质量的出发点,本身定了相关的性能优化方案,可能不太成熟。只是可以逐步无缺。并找到最适合本身产品的优化方案。缓存

这里我定了四个方向:
- 响应时间(Response Time)
- 界面卡顿(ANR)
- 耗内存(Memory)
- 内存泄露(Out of memory)安全

响应时间

这里指的是client与服务端交互,拿到数据、解析、再到显示到界面整个过程耗费的时间。性能优化

这个部分涉及client的优化。也涉及服务端的优化,这里仅仅讨论client。markdown

HTTP请求方式

咱们的app通常离不开网络,请求接口是最寻常的操做了,怎样请求,请求什么咱们在开发初期就要定好,服务端给个人提供的接口,大体可以经过GET、POST、HEAD、PUT、DELETE这几种请求方式,不一样的请求方式有不一样应用场景,比方GET请求。应当用来请求返回结果。參数是做为url的一部分;POST请求。用于请求会更改服务端数据或状态。HEAD请求跟GET同样。仅仅是server不能在响应里返回消息主体;PUT请求,用于将网页放置正确的地方;DELETE请求用于删除server指定文档。网络

使用优秀的开源Http框架是咱们比較好的选择。它的优势是通过市场的验证,很是多坑都被填过,缺点也是咱们需要去深究它才干对其进行扩展。遇到坑也不必定能填。app

假设本身造轮子的话。还需要咱们花时间去验证去适应咱们的业务需求,但优势是咱们可以本身去扩展可把控,只是这很是考量开发人员的素养。框架

数据解析

实际开发其中服务端的返回数据格式无非就两种:
- JSON
- XMLdom

这两种格式数据格式各有优劣。从可读性来看,xml稍微好一点,只是JSON也有规范的标签,从解析难度和速度来看,你们都比較倾向使用JSON,眼下JSON也是主流的数据格式。异步

在Android中均可以使用优秀的解析库来加快咱们的解析速度,XML中有dom4j,JSON有Jackson、Gson。咱们经过这些库实现咱们更快的完毕数据解析,提升咱们的开发效率。

数据存储

上一节讲的是数据解析。咱们解析完后的数据,可能就需要将数据存储在某个地方,Android的五种存储方式:
- Content Provider(主要用来向其它应用程序共享数据)
- SQLite(存储数据到数据库中)
- File(本地文件保存)
- SharedPreference(主要用来保存简单的配置信息)
- 网络存储(WebService返回的数据或是解析HTTP协议实现网络数据交互)

为了提升应用程序的响应时间,数据缓存是一个比較好的方式,咱们可以预处理server返回的数据,对数据进行缓存刷新。

优化点:
- 异步请求网络数据
- 预处理server返回数据
- 异步进行数据存储操做
- 数据缓存刷新
- Timeout超时重试
- 在主线程中操做UI

界面卡顿

ANR表示”应用程序无响应”,这个是需要咱们避免发生的事情,出现这个异常的缘由:
- 主线程 (“事件处理线程” / “UI线程”) 在5秒内没有响应输入事件
- BroadcastReceiver在10秒内没有运行完毕

致使ANR的缘由有很是多,普通状况就是在UI线程作了耗时的操做,好比”网络请求”、数据库操做。

那么怎样避免?
- UI线程仅仅作界面刷新,不作不论什么耗时操做。耗时操做放在子线程来作
- 可以使用Thread+handle或者AsyncTask来进行逻辑处理

耗内存

每部手机的内存有限,咱们这里所说的内存指的是手机的RAM,它是Ramdom Access Memory的缩写。咱们应用程序的需要随机读写的数据就存在RAM中,Android手机之因此会比較耗内存。这跟Android后台的处理有关,咱们知道Android应用是使用Java开发的。运行Java需要有虚拟机,说明每开启一个应用都会建立一个虚拟机。而这是需要内存的,因此咱们开的应用越多,后台进程越多。内存都分配出去了,才致使内存消耗的严重。

事实上这个问题咱们是没得破的,仅仅要内存不够。咱们的应用仍是会卡。咱们开发的应用依赖与系统给咱们分配的堆内存,通常上限在16M~48M,但咱们可以经过在AndroidManifest设置Application属性largeHeap=“true”来申请不少其它的堆内存。

经过下面代码获取可用堆内存限制:

mActivityManager = (ActivityManager) this.getSystemService(Context.ACTIVITY_SERVICE);
 mMaxMemory = mActivityManager.getMemoryClass();

内存泄露

内存泄露这个问题已经被说烂了。你们都知道有内存泄露这个问题存在,但为何会发生内存泄露?

这里的内存泄露并不是真正意思上的泄露。而是因为内存不足不能进行GC操做,从而致使占用内存过大。抛出out of memory异常,而被系统Kill掉。

JVM回收机制

是时候讲讲JVM的回收机制了。看下图:

JVM分代

JVM对Java对象分了三个代进行管理。分别为年轻代、年老代、永久代。
年轻代(Young Generation):绝大多数的Java对象会在年轻代被分配,也会在年轻代被回收。
年老代(Old Generation):在年轻代长期存在没有被回收的Java对象会转移到年老代,这个堆空间通常会被比年轻代的堆空间要大。


永久代:存放VM和Java类的元数据。以及interned字符串和类的静态变量。

这里涉及到JVM的相关知识,这里不继续深刻探讨。

但咱们应该可以知道垃圾回收器的做用:
- 分配内存
- 保证所有正在被引用的对象还存在于内存中
- 回收运行代码已经再也不引用的对象所占的内存

对象引用

Java的引用类型可以分为下面几种:
- 强引用(Strong Ref):强可达,去掉强可达,才会被回收。


- 软引用(Soft Ref):内存够用。就保持,内存吃紧。则回收,主要用来作缓存。
- 弱引用(Weak Ref):比Soft Ref弱,即便内存不吃紧也会被回收。


- 虚引用(Phantom Ref):不会在内存保持不论什么对象。

一图胜千言:

对象引用

利用Strong Ref,存储大量数据。直到heap撑破,利用inter strings(或者class loader载入大量的类)把perm gen撑破,而后就是内存泄露了。

怎样优化?

前面讲了一些背景知识,对咱们理解内存优化有必定的帮助,下面就简单说一下咱们优化的方向:
- 布局优化
- 内存优化

布局优化

你们可以拿出大家的Android机
开发人员工具-Profile GPU Rendering-选择在屏幕上显示条形图

-蓝色表明測量绘制Display List的时间
-红色表明OpenGL渲染Display List所需要的时间
-黄色表明CPU等待GPU处理的时间
-中间绿色横线表明VSYNC时间16ms。尽可能将所有条形图控制在这条绿线下

为何是16ms?

Android 通知界面渲染和重绘的时间要在16ms内完毕。假设超过16ms,就会致使丢帧,也就是咱们常说的卡顿。

优化点:
- 避免OverDraw
- 优化布局层级
- 避免过多无用嵌套
- 使用<include>标签重用layout
- 使用<ViewStub>延迟载入
- Hierarchy View进行层级分析

详细的用法,这里不介绍了,不懂就百度。

内存优化

内存优化的点有很是多,这里我主要分为两大块:
- Bitmap优化
- 代码优化

Bitmap优化

  1. 使用适当分辨率和大小的图片
  2. 及时回收内存(bitmap.recycle())
  3. 使用图片缓存(LruCache和DiskLruCache)

第一点,就是按需显示。比方列表中的图片,你可以显示缩略图,详情页,你就可以载入对应的分辨率的图片。这样可以下降内存消耗,通常可以要求服务端提供多种分辨率的图片。

第二点。Bitmap是很是耗内存,尤为是载入比較大的bitmap,可以想到的优化方案就是使用记得回收,对Bitmap进行压缩,使用BitmapFactory.Options设置inSampleSize就可以缩小图片。

第三点。图像缓存,这个可以利用成熟的图片载入框架,比方Universal-ImageLoader、Fresco、Picasso,这些框架都对图片进行了很是好的优化,你们可以对照一下,选择使用就能够。

代码优化

关于代码这个就有的说了,不论什么能改进咱们程序的优化点都能写在这里,这里没办法把所有优化的点列在这里,仅仅提供相关的參考,剩下的就好各位经验总结和积累了。

优化点:
- 对常量使用static修饰符
- 使用静态方法
- 下降没必要要的成员变量
- 尽可能不要使用枚举。少用迭代器
- 对Cursor、Receiver、Sensor、File等对象。要注意它们的建立、回收与注冊、反注冊
- 避免大量使用注解、反射
- 使用RenderScript、OpenGL来进行复杂的画图操做
- 使用SurfaceView来替代View进行大量、频繁的画图操做
- 尽可能使用视图缓存,而不是每次都运行inflate()方法解析视图

注:这里引用了Android群英传的相关优化点

  • 建立新的对象都需要额外的内存空间。要尽可能下降建立新的对象。
  • 将类、变量、方法等等的可见性改动为最小。
  • 针对字符串的拼接,使用StringBuffer替代String。
  • 不要在循环其中声明暂时变量,不要在循环中捕获异常。

  • 假设对于线程安全没有要求,尽可能使用线程不安全的集合对象。
  • 使用集合对象,假设事先知道其大小。则可以在构造方法中设置初始大小。

  • 文件读取操做需要使用缓存类。及时关闭文件。
  • 慎用异常,使用异常会致使性能下降。
  • 假设程序会频繁建立线程,则可以考虑使用线程池。

以上都是些经验总结,大体都相差无几,朋友们在作代码优化的时候。可以依据这些优化点,有针对性去重构代码,事实上最重要仍是代码的可读性,结构清晰。

性能优化工具

  • Memory Monitor - 内存监视工具
  • TraceView
  • MAT

Android开发人员对与以上几个性能调优的工具必定不陌生。这里我也再也不写那么多废话了,关于它们的用法,官网另外一些大牛的博客都有介绍。

最后

写这篇文章的出发点也是对Android性能优化有个比較清晰的认识,不论什么事情都不可能一蹴而就,需要循循渐进,对一个刚開始学习的人你谈优化很是不现实。咱们先把主要的作好,再去考虑对应的优化,笔者也在不断学习其中。借鉴别人好的优化方案,提升产品的质量。感谢你们对笔者的关注。

相关文章
相关标签/搜索