简介


本文记录使用工具来对app进行优化过程,主要包括UI界面优化、内存优化、代码优化以及电量优化;各个优化模块是相互关联的,各个模块优化后才能达到app整体的性能提升。


UI界面优化

界面优化方面主要是减少GPU过渡绘制(也就是同一个像素点多次绘制)以及优化渲染时间,优化点主要是:

  • 减少布局层次空间
  • 视图View的绘制draw方法减少耗时操作
    如何才能完成上述的布局优化,本篇不做阐述,可以查看我的GPU调试笔记

代码优化

代码优化范围就很广,涉及的知识也很多!首先,在编码时,我们要打造一个 适合具体项目代码框架,复用相同的代码,打造高内聚、低耦合的代码;不同业务场景使用不同的数据结构,权衡时间和空间效率,复杂耗时操作要活用线程或者进程;然后,当我们编写好代码后,我们反向来检查优化代码时,可以使用一些工具来优化代码


monkey压力测试

monkey是adb中的一个测试脚本工具,当我们输入命令后,monkey可以模拟点击、滑动、长按等操作,随机去操控我们的App,以检测App中意料之外的bug,最后输出一份测试日志文件供我们去查看出现的bug;具体的monkey测试步骤如下:
操作指令:

adb shell monkey -p packagename -s 20 --throttle 1500 --ignore-crashes --ignore-timeouts -vvv 1000

-p: 测试的包名
-s: 种子数,可以理解为各种触摸点击次数顺序是通过一个算法实现的,而这个算法需要输入一个时间因子,相同的时间因子,产生的触摸事件是一模一样的
–ignore-crashes --ignore-timeouts: 忽略测试过程中产生异常和超时,否则测试会终止
-v:表示日志等级,默认是v,vvv是verbose最详细等级
1000:表示事件的次数
–throttle:事件操作后的延时
为了保证测试覆盖App所有页面,可以写个脚本,多执行几次,变换不同的时间因子;最后去日志文件查询崩溃日志
此项功能要打开USB模拟点击功能,不然无法调试


UI优化总结

  • 布局不要嵌套太多层
  • 使用merge减少布局
  • 自定义View onDraw不要放置复杂操作
  • 合理使用validate和requestLayout

TraceView工具优化代码

当我们调试代码时,如遇到某段业务逻辑执行速率慢时,无法定位出哪块代码导致时,可以使用traceView工具进行定位;traceView工具可以展示代码执行的耗时、次数
该工具位于android sdk的tools/monitor目录下

先来看一下traceView工具界面

如上图:
区域A:展示的是多个线程以及线程号
区域B:A区域每个线程执行函数的时间分布图,线程中每个函数标记为一种唯一的颜色,颜色的长度标明这个函数执行时间的长度;所以从这个分布图中可以很明确的找出谁执行得慢
区域C:和区域B相关,每个函数的执行速率结果,还有函数执行顺序,当前函数由谁调起,它又调用了哪些其他函数;重点阐述横向的参数:
incl cpu time:函数获取CPU时间片执行时间,包含函数内部调用其他函数时间;
excl cpu time:函数自身CPU执行时间,不包含调用的下级函数时间
incl real time:函数执行时间,包括函数内调用其他函数时间,也包含被线程中断休眠阻塞的时间
excl real time:同上,但是不包括调用其他函数时间
Calls+RecurCalls/Total:程序调用次数+递归调用次数/总次数
Cpu Time/Call:函数执行获取时间片平均时间
Real Time/Call:函数执行时间包括休眠时间,平均时间


如何快速找出效率低函数?

两个关键点:(1) 函数本身比较耗时;(2) 函数调用次数过多

首先,可以很直观的在上图B区域,快速找出颜色最长的也就是函数耗时最长的;其次,也可以在C区域点击CPU TIme/Call,C区域会自动排序长度;同理点击Calls+RecurCalls/Total自动排序调用次数;但是C区域函数比较多,我们可以在C区域下方有个Find进行输入过滤,能快速找到低效率函数,然后我们去查看逻辑进行优化即可


优化demo

下面,我将使用上述方法来优化一段打开相机扫一扫的逻辑,进行优化:

  1. 首先从主观感受上,我打开相机感觉比较慢,我需要定位trace代码的启动和终点
  2. 起点我使用Debug.startMethodTracing(“xxx.trace”)进行开启trace起点,假设扫一扫页面为ScanActivity;那我这个起点在打开这个页面的前一句代码
  3. 终点我设置在ScanActivity的onWindowFocusChanged方法,该方法表明activity真正可见,不要设置到onResume;使用Debug.stopMethodTracing();停止trace
  4. 最后运行app完成后,会在/sdcard/Android/data/packageName/files/xxx.trace路径下,adb pull出来
  5. 使用monitor打开这个文件;以下是我对trace文件的分析:
    注意,定位trace代码块除了上面的Debug插入代码这种方法外;还可以直接使用studio的Profile功能,在CPU性能图下面,直接点击trace start和stop
    优化点1,相机参数getParameters

    通过CPU Time/Calls排序后,加上书图com过滤后发现:
    早SurfaceCreated函数内部耗时的原因是initCamera和isFlashing这两个函数;进入这两个子函数查看:


    如上两图,在isFlashlightAvailable和initCamera两个方法内主要的耗时都在Camera.getParameters这个函数,进一步查看函数:
public Parameters getParameters() {Parameters p = new Parameters();String s = native_getParameters();//耗时主要在下面这个方法p.unflatten(s);return p;
}

p.unflatten会遍历相机的所有参数并封装构造到一个Map结构;这也是它耗时的原因,并且这个函数是库函数无法修改;但是我们程序多个函数都回去掉这个函数,处理的办法就是缓存获取的相机参数,并且为了保持参数的有效性,加入了一个过期时间;修改如下:

private Camera.Parameters getCamerPara(){if(cachParams == null || System.currentTimeMillis() - lastParaTime > 60000){cachParams = mCamera.getParameters();lastParaTime = System.currentTimeMillis();}return cachParams;
}

把之前的用到Camera.getParameters()的地方全部改为这个函数即可;优化后重新trace结果如下图:


优化点2,setContentView布局
从traceView文件中发现setContentView也比较耗时:

setContentView时间的长短取决于布局文件xml的层叠嵌套,查看布局发现,根部据里面嵌套了一层ToolBar,在ToolBar里面有我们的左右标题TextView;我修改为去掉ToolBar布局,把左右布局提出来在根布局下面,这样整个布局文件就只有一层布局了
最后,优化后trace的结果,setContentView耗时减少:

优化总结

  • 复杂耗时逻辑放入子线程、进程或者服务端
  • 一些网络请求使用缓存
  • 大量数据分批操作,如在屏幕内时才加载 屏幕外不加载
  • 使用Service后台进行

内存优化Profile

移动端设备内存有限,需要合理使用内存资源,及时释放不需要的内存,减少内存泄漏;这里用到的工具是Android Studio的Profile,点击Run下面的Profile功能,进入MEMORY内存下面,大致如下图所示:

简单介绍下上述界面各个区域:
C区域:内存时间线,内存是实时的,可以查看过去到现在任意时刻的内存状况,内存增加时,图形会上升,内存释放或者垃圾回收时,图形会下降,如C区域右下角的垃圾桶符号就是一个垃圾回收标志。

B区域:垃圾桶标志,点击后就会主动进行垃圾回收;下载符号,是对app内存进行dump标志,后面的allocation Tracking菜单选项,是内存app dump选项,有sample和full选项,sample方式dump内存是对app影响较小,而full较大;dump内存后,内存明细就时上图下班部分的样子

A区域:实时展示app内各个模块内存大小;

  • java 从java或kotlin代码分配的对象内存
  • native 从C/C++代码分配的内存
  • Graphics 从图像缓冲队列输出到屏幕的像素(如GL表面/GL纹理)所占用的内存
  • Stack 应用中原生堆栈和java堆栈所用的内存
  • Code 代码资源(dex字节码/dex优化字节码/so库和字体等)
  • others 应用占用的内存系统无法归类
  • Allocated java和kotlin代码的对象个数

D区域:dump的内存实例详细展示,左上方方框内是查看方式选择;

  • default heap:当系统未指定堆时。
  • image heap:系统启动映像,包含启动期间预加载的类。此处的分配保证绝不会移动或消失。
  • zygote heap:写时复制堆,其中的应用进程是从 Android 系统中派生的。
  • app heap:您的应用在其中分配内存的主堆。
  • JNI heap:显示 Java 原生接口 (JNI) 引用被分配和释放到什么位置的堆。

右侧的菜单中,选择如何安排分配:

  • Arrange by class:根据类名称对所有分配进行分组。这是默认选项。
  • Arrange by package:根据软件包名称对所有分配进行分组。
  • Arrange by callstack:将所有分配分组到其对应的调用堆栈。

D区域右侧还有许多菜单:
Allocations:java内存实例数量
native size:此java对象使用的native层的内存量,字节单位
shallow size:此java对象使用java内存总量
Retained Size:为此类的所有实例而保留的内存总大小

当我们选择D区域某个对象实例时,会在右侧展示EF区域
E区域:为D区域该实例拥有的所有成员变量

  • depth 对象实例到GC根节点的跳数
  • Native Size:java对象所有所拥有native层的占用的内存
  • shallow size和Retained Size同上

F区域:对象实例被别的对象持有的引用
memory的功能介绍完了,那这个工具是如何进行内存优化呢?
首先,需要给app一些压力,极限测试下,实时查看内存分配请看,有没有内存激增的异常状况;其次,主动垃圾回收后,dump内存下来,查看内存实例,主要看内存泄漏,一些该释放而没有被释放的实例。这里我们也可以配合monkey测试框架自动完成内存优化

profile memory例子

我所采用的调试方法:
我先使用monkey自动测试,随机操作app,最后然其停留在主页面HomePage,手动点击垃圾回收,dump内存查看检查,和主页面不相关的实例都不应该存在,需要检查实例的对象数量,占用内存是否太大不合理等;app的其他页面也类似,都可以按照此操作进行,以下时我dump内存发现的异常问题:

实例数量过多


ServiceCreator这个类时我底层网络框架的基础类,网络访问接口都是由这个类生成的;我代码设计的本意ServiceCreator时唯一的,不会存在多个实例,那这里时不对的,查看源码如下:

//网络底层服务
@Binds
abstract IServiceCreator serviceCreator(ServiceCreator serviceCreator);

我使用的时dagger2框架,这里采用的时@Binds接口和实例绑定,而问题出在没有给他设置单例唯一,解决的办法加个注解@Singleton解决问题;不清楚dagger2的可以参考这篇文章

下面截图也是实例过多,同一个实例高达6个

查看这段源码:

window.findViewById(R.id.tv_mv_phone).setOnClickListener(this::onClickViews);
window.findViewById(R.id.tv_check_user).setOnClickListener(this::onClickViews);
window.findViewById(R.id.tv_check_private).setOnClickListener(this::onClickViews);
window.findViewById(R.id.about_us).setOnClickListener(this::onClickViews);
window.findViewById(R.id.btn_logout).setOnClickListener(this::onClickViews);
userIcon = window.findViewById(R.id.btn_login);
userIcon.setOnClickListener(this::onClickViews);

上面使用lambda表达式设置组件view监听,熟悉lambda表达式原理的人都知道这时怎么回事,不熟悉的点击这里,解决的办法就是不用lambda,直接设置为一个监听


Profile里面的Network和Energy调试

这两块主要网络模块和能耗模块,查看网络流以及一些服务能耗。
关于Network模块,查看一些网络访问数据和频率,减少不必要的发送数据,以及减小发送频率;
Energy模块,主要是一些服务耗电,如定位等,不使用定位时,关闭定位服务。

以上就是性能调试的记录!如有不正或更好的办法,望不吝赐教!

android使用工具性能优化相关推荐

  1. 转:Android应用开发性能优化完全分析

    转自:http://blog.csdn.net/yanbober/article/details/48394201 1 背景 其实有点不想写这篇文章的,但是又想写,有些矛盾.不想写的原因是随便上网一搜 ...

  2. Android应用开发性能优化完全分析

    1 背景 其实有点不想写这篇文章的,但是又想写,有些矛盾.不想写的原因是随便上网一搜一堆关于性能的建议,感觉大家你一总结.我一总结的都说到了很多优化注意事项,但是看过这些文章后大多数存在一个问题就是只 ...

  3. Android应用程序性能优化

    1 背景 其实有点不想写这篇文章的,但是又想写,有些矛盾.不想写的原因是随便上网一搜一堆关于性能的建议,感觉大家你一总结.我一总结的都说到了很多优化注意事项,但是看过这些文章后大多数存在一个问题就是只 ...

  4. android 内存和性能优化汇总

    1.即时编译(Just-in-time Compilation,JIT),又称动态转译(Dynamic Translation),是一种通过在运行时将字节码翻译为机器码,从而改善字节码编译语言性能的技 ...

  5. ym——Android之ListView性能优化

    转载请注明本文出自Cym的博客(http://blog.csdn.net/cym492224103),谢谢支持! Android之ListView性能优化 假设有看过我写过的15k面试题的朋友们一定知 ...

  6. Android进阶:性能优化篇 Android进阶:性能优化篇

    Android进阶:性能优化篇 分类:Android 性能优化2011-08-09 17:06585人阅读评论(0)收藏举报 一.在使用Gallery控件时,如果载入的图片过多,过大,就很容易出现Ou ...

  7. 抖音Android岗面试性能优化篇之Rhea(新一代全能型性能分析工具)【速看】

    写在前面的话 性能优化这个知识点是很多大厂面试中都会问到的问题,尤其是想要面试抖音的Android岗的朋友. 用户交互响应的耗时,作为 Android 用户日常感知最深的一项性能指标,在日常开发中有着 ...

  8. Android开发——布局性能优化的一些技巧(一)

    0. 前言 上一篇我们分析了为什么LinearLayout会比RelativeLayout性能更高,意义在于分析了这两种布局的实现源码,算是对一个小结论的证明过程,但是对布局性能的优化效果,对这两种布 ...

  9. android的UI性能优化

    设计师,开发人员,需求研究和测试都会影响到一个app最后的UI展示,所有人都很乐于去建议app应该怎么去展示UI.UI也是app和用户打交道的部分,直接对用户形成品牌意识,需要仔细的设计.无论你的ap ...

最新文章

  1. 17.Java5的Exchanger同步工具
  2. 只要暴风骤雨才能使人迅速地成长
  3. 参数修饰符 params、in
  4. 学习如何用自己的 appender 来扩展 log4j 框架
  5. Equipment delta download debug from ERP side
  6. 计算机设备操作与讲解,计算机组成与操作系统简介
  7. [轻微]WEB服务器启用了OPTIONS方法/如何禁止DELETE,PUT,OPTIONS等协议访问应用程序/tomcat下禁用不安全的http方法...
  8. centos下mysql 命令_CentOS下mysql数据库常用命令总结
  9. popen 如何获取指令执行情况_Linux下使用popen()执行shell命令
  10. 巧改注册表拥有超级cpu
  11. Uva 11178 Morley定理
  12. c 语言重载参数类型不同重载和,C/C++函数重载与缺省参数
  13. 论文阅读-可变形卷积v2: More Deformable, Better Results
  14. vb6源码 ymodem_VB爱好者乐园(VBGood)
  15. 查询oracle中所有的用户,如何查询Oracle中所有用户信息
  16. Grid 布局实现九宫格图片动画
  17. Java每日一练(1)
  18. Odoo客户成功案例访谈:机加工厂企业信息化的心路历程探讨
  19. 反向代理方式实现IIS与Tomcat整合
  20. 多元线性回归及案例(Python)

热门文章

  1. java 对象为空异常,Java空对象(null)是怎么回事?
  2. 如何用3个月零基础入门网络安全?
  3. [ML]归纳学习与机器学习概述
  4. Simulink 0基础入门教程
  5. JavaWeb开发实现一个动态页面
  6. Linux离线安装NTP服务,内网环境下配置本地时间同步
  7. 扒一扒你不知道的《经济学人》大家族
  8. 联想乐檬k3刷安卓5.1教程
  9. 微信小程序运动减肥+后台管理系统
  10. 漫画:如何盗刷别人的支付宝?