前言

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

从何讲起?

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

这里我定了四个方向:

- 响应时间(Response Time)

- 界面卡顿(ANR)

- 耗内存(Memory)

- 内存泄露(Out of memory)

响应时间

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

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

HTTP请求方式

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

使用优秀的开源Http框架是我们比較好的选择。它的优点是经过市场的验证,非常多坑都被填过,缺点也是我们须要去深究它才干对其进行扩展。遇到坑也不一定能填。

假设自己造轮子的话。还须要我们花时间去验证去适应我们的业务需求,但优点是我们能够自己去扩展可把控,只是这非常考量开发人员的素养。

数据解析

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

- JSON

- XML

这两种格式数据格式各有优劣。从可读性来看,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对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性能优化有个比較清晰的认识,不论什么事情都不可能一蹴而就,须要循循渐进,对一个刚開始学习的人你谈优化非常不现实。我们先把主要的做好,再去考虑对应的优化,笔者也在不断学习其中。借鉴别人好的优化方案,提高产品的质量。感谢大家对笔者的关注。

App性能优化浅谈的更多相关文章

  1. web server性能优化浅谈

    作者:ZhiYan,Jack47 转载请保留作者和原文出处 Update: 2018.8.8 在无锁小节增加了一些内容 性能优化,优化的东西一定得在主路径上,结合测量的结果去优化.不然即使性能再好,逻 ...

  2. sql性能优化浅谈

    sql性能优化总结: 最近随着数据越来越多,数据库性能问题暴露的越来越严重.几百万,上千万,甚至过亿的数据处理速度会非常的慢. 下面对工作中遇到的问题做下总结,希望以后能对日后的工作有所帮助. 不同的 ...

  3. pb传输优化浅谈

    在正式切入今天要谈的优化之前,先碎碎念一些自己过去这几年的经历.很久没有登录过博客园了,今天也是偶然兴起打开上来看一下,翻看了下自己的随笔,最后一篇原创文章发布时间是2015年的4月,今天是2017年 ...

  4. MYSQL优化浅谈,工具及优化点介绍,mysqldumpslow,pt-query-digest,explain等

    MYSQL优化浅谈 msyql是开发常用的关系型数据库,快速.稳定.开源等优点就不说了. 个人认为,项目上线,标志着一个项目真正的开始.从运维,到反馈,到再分析,再版本迭代,再优化… 这是一个漫长且考 ...

  5. fir.im Weekly - 如何进行 Android App 性能优化

    关于 Android App 的优化,@anly-jun 用 3 个月完成了这一系列文章,从 性能分析工具 到 ANR .Layout .消除卡顿 到 内存优化.内存分析工具大概十五六篇,并对此做一个 ...

  6. Android APP 性能优化的一些思考

    说到 Android 系统手机,大部分人的印象是用了一段时间就变得有点卡顿,有些程序在运行期间莫名其妙的出现崩溃,打开系统文件夹一看,发现多了很多文件,然后用手机管家 APP 不断地进行清理优化 ,才 ...

  7. 包建强的培训课程(9):Android App性能优化

    v\:* {behavior:url(#default#VML);} o\:* {behavior:url(#default#VML);} w\:* {behavior:url(#default#VM ...

  8. Android app 性能优化的思考--性能卡顿不好的原因在哪?

    说到 Android 系统手机,大部分人的印象是用了一段时间就变得有点卡顿,有些程序在运行期间莫名其妙的出现崩溃,打开系统文件夹一看,发现多了很多文件,然后用手机管家 APP 不断地进行清理优化 ,才 ...

  9. android app性能优化大汇总

    这里根据网络上各位大神已经总结的知识内容做一个大汇总,作为记录,方便后续“温故知新”. 性能指标: (1)使用流畅度:  图片处理器每秒刷新的帧数(FPS),可用来指示页面是否平滑的渲染.高的帧率可以 ...

随机推荐

  1. Welcome-to-Swift-07闭包(Closures)

    闭包是自包含的函数代码块,可以在代码中被传递和使用. Swift 中的闭包与 C 和 Objective-C 中的代码块(blocks)以及其他一些编程语言中的 lambdas 函数比较相似. 闭包可 ...

  2. python输出字典中的中文

    如果不用本文指定的方法,会有如下报错: UnicodeDecodeError: 'utf8' codec can't decode byte 0xbf in position 2: invalid s ...

  3. 页面之间传值的方法asp

    原文发布时间为:2008-06-02 -- 来源于本人的百度文章 [由搬家工具导入] asp.net页面间传值 今天学习中要在两个页面中传值,网上搜了一下,asp.net主要用到三个方法,前两个req ...

  4. poj 3281(构图+网络流)

    Dining Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 14144   Accepted: 6425 Descripti ...

  5. LeetCode OJ——Binary Tree Inorder Traversal

    http://oj.leetcode.com/problems/binary-tree-inorder-traversal/ 树的中序遍历,递归方法,和非递归方法. /** * Definition ...

  6. 解决 ecshop 搜索特殊字符关键字(如:*,+,/)导致搜索结果乱码问题

    病症:ecshop系统搜索会对搜索关键字进行分词,然后对关键字分词进行正则匹配,并且标红加粗处理,如果关键字分词有特殊字符,则正则匹配结果会导致乱码 解决方法: 1.找到特殊字符串数组:$ts_str ...

  7. ELK之收集haproxy日志

    由于HAProxy的运行信息不写入日志文件,但它依赖于标准的系统日志协议将日志发送到远程服务器(通常位于同一系统上),所以需要借助rsyslog来收集haproxy的日志.haproxy代理nginx ...

  8. Ext 上传文件

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"/> <title> ...

  9. IOS开发之----两种保存用户名和密码实现记住密码库

    使用Keychain存储用户敏感信息 iOS的keychain服务提供了一种安全的保存私密信息(密码,序列号,证书等)的方式,每个ios程序都有一个独立的keychain存储.相对于 NSUserDe ...

  10. Android获取状态栏和标题栏的高度

    版权声明:本文为博主原创文章,未经博主允许不得转载. 1.获取状态栏高度: decorView是window中的最顶层view,可以从window中获取到decorView,然后decorView有个 ...