android 卡顿代码定位,Android 性能优化实例:通过 TraceView 定位卡顿问题

66b52468c121889b900d4956032f1009.png

8种机械键盘轴体对比

本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选?

背景

项目中使用了鸿洋大神的TreeView树状结构控件, 但是由于在主线程中使用了注解/反射来定位节点, 内容一多就有点卡顿。因此通过android device monitor中的性能分析工具定位并优化这一问题并记录过程。

准备工作打开tools菜单 —— android——android device monitor

选中要追踪的app进程——点击Start Method Profiling

操作想要追踪问题的界面或行为使问题暴露

在刚才的按钮点击stop

start_trace.png

分析

卡顿根本原因由于Ui渲染被阻塞造成,它运行在主线程, 因此主线程也被称为UI线程。

原因可能有很多,常见的有主线程中执行速度较慢的I/O操作造成CPU等待, 或主线程有其他大量任务占满了CPU, 比如程序没写好死循环了 - - 。

那么我们在这边主线程没有做I/O操作, 因此先按 Excl Cpu Time % 排序, 查看CPU占用百分比 。

定位到 no.18 的方法占用了30.4%, 点选他之后 , 看到 【1】main 主线程中后面大部分都变色, 表明是这个method的执行区间。 卡顿罪魁祸首就是它了!

cpu_consume_define.png

点开方法名左边小箭头, parent表示是被哪个父方法调用, children是表示调用的所有子方法。

点开children分析后面几个参数Incl Cpu Time 表示各子方法的总运行时长, 主要就看他定位具体方法

Incl Cpu Time % 就是各子方法的分配到的CPU占比

calls+RecurCalls/Total 表示被调用的次数 (大致符合逻辑就行 主要是看不是异常大 判断死循环)

找到性能表现有问题的方法后一个一个双击看下去就可以了, 同时结合上半部分界面的运行时图表也能直观看出资源占用的区间

child_cunsume_define.png

优化

看一下排前5的几个方法, 2个属于反射获取Annotation和Filed, 反射是众所周知的慢, 先放过他们, 另外3个我们看一下方法内容

/**

* 将我们的数据转化为树的节点

*

* @param datas

*

* @return

*

* @throws NoSuchFieldException

* @throws IllegalAccessException

* @throws IllegalArgumentException

*/

private static List convetData2Node(List datas)

throws IllegalArgumentException, IllegalAccessException

{

List nodes = new ArrayList();

Node node = null;

for (T t : datas) {

int id = -1;

int pId = -1;

int pnode = -1;

String label = null;

Class extends Object> clazz = t.getClass();

Field[] declaredFields = clazz.getDeclaredFields();

for (Field f : declaredFields) {

if (f.getAnnotation(TreeNode.class) != null) {

f.setAccessible(true);

pnode = f.getInt(t);

}

if (f.getAnnotation(TreeNodeId.class) != null) {

f.setAccessible(true);

id = f.getInt(t);

}

if (f.getAnnotation(TreeNodePid.class) != null) {

f.setAccessible(true);

pId = f.getInt(t);

}

if (f.getAnnotation(TreeNodeLabel.class) != null) {

f.setAccessible(true);

label = (String) f.get(t);

}

if (pnode != -1 && id != -1 && pId != -1 && label != null) {

break;

}

}

node = new Node(pnode, id, pId, label);

nodes.add(node);

}

/*

* 设置Node间,父子关系;让每两个节点都比较一次,即可设置其中的关系

*/

for (int i = 0; i < nodes.size(); i++) {

Node n = nodes.get(i);

for (int j = i + 1; j < nodes.size(); j++) {

Node m = nodes.get(j);

if (m.getpId() == n.getId()) {

n.getChildren().add(m);

m.setParent(n);

} else if (m.getId() == n.getpId()) {

m.getChildren().add(n);

n.setParent(m);

}

}

}

// 设置图片

for (Node n : nodes) {

setNodeIcon(n);

}

return nodes;

}

反射创建节点后通过for循环设置节点的上下级关系, 就是这个for循环有问题了。getId和getPid方法

鸿洋大神的Node类是个标准javaBean, 也就是属性全部private通过get, set操作。but, 这样会比直接读属性慢10倍左右, 其实也没啥大不了, but 如果被调用很多次。。。我把 id 和 pid 改成public 并删掉 get set方法

ArrayList.size()

这个也很简单,直接在for循环里定义下变量。改完后的for循环如下

/*

* 设置Node间,父子关系;让每两个节点都比较一次,即可设置其中的关系

*/

for (int i = 0, a = nodes.size(); i < a; i++) {

Node n = nodes.get(i);

for (int j = i + 1; j < a; j++) {

Node m = nodes.get(j);

if (m.pId == n.id) {

n.getChildren().add(m);

m.setParent(n);

} else if (m.id == n.pId) {

m.getChildren().add(n);

n.setParent(m);

}

}

}

效果如下图, 虽然cpu%提高了,但那是由于其他耗时方法不见了,因此总占比就高了,具体看children分类下面,那3个耗时较长的方法已经不见了,self分类的时间也有所降低。 因此incl Cpu Time从2938降低到了1096毫秒,效果还是比较显著的

after_optimize.png

虽然方法优化完了,但还是有1秒的卡顿存在, 因此我后来又改了下把转换节点的操作放到子线程执行了,这就不详细讲了。

总结使用Android Device Monitor工具, 捕获问题发生时的方法执行信息

按Excl Cpu Time % 排序, 找到需要优化的方法

查看方法的children列表, 分析Incl Cpu Time 和 calls+RecurCalls/Total是否合理

找到并修改方法

再次捕获信息, 对比分析

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/310777.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DotNetCore三大Redis客户端对比和使用心得

前言稍微复杂一点的互联网项目&#xff0c;技术选型都会涉及Redis&#xff0c;.NetCore的生态越发完善&#xff0c;支持.NetCore的Redis客户端越来越多&#xff0c;下面三款常见的Redis客户端&#xff0c;相信大家平时或多或少用到一些&#xff0c;结合三款客户端的使用经历&am…

android elevation 白色,Android Elevation

简介&#xff1a;在Android API21&#xff0c;新添加了一个属性&#xff1a;android:elevation&#xff0c;用以在xml定义View的深度(高度)&#xff0c;也即z方向的值。除了elevation之外&#xff0c;类似于已有的translationX、translationY&#xff0c;也相对应地新增了一个t…

(译)创建.NET Core多租户应用程序-租户解析

介绍本系列博客文章探讨了如何在ASP.NET Core Web应用程序中实现多租户。这里有很多代码段&#xff0c;因此您可以按照自己的示例应用程序进行操作。在此过程的最后&#xff0c;没有对应的NuGet程序包&#xff0c;但这是一个很好的学习和练习。它涉及到框架的一些“核心”部分。…

【要闻】Kubernetes无用论诞生、Elasticsearch 7.6.2 发布

导读&#xff1a;本期要闻包含OpenStack网络如何给组织带来好处、Portworx CEO分享的如何让Kubernetes跑得快还不出错的秘籍等精彩内容。大数据要闻Elasticsearch 7.6.2 发布&#xff0c;分布式搜索和数据分析引擎Elasticsearch 7.6.2 发布了&#xff0c;Elasticsearch 是一个分…

玩转控件:对Dev中GridControl控件的封装和扩展

清明节清明时节雨纷纷路上行人欲断魂借问酒家何处有牧童遥指杏花村又是一年清明节至&#xff0c;细雨绵绵犹如泪光&#xff0c;树叶随风摆动....转眼间&#xff0c;一年又过去了三分之一&#xff0c;疫情的严峻让不少企业就跟清明时节的树叶一样&#xff0c;摇摇欲坠。裁员的裁…

创业5年,我有5点关于人的思考

点击蓝字关注&#xff0c;回复“职场进阶”获取职场进阶精品资料一份不知不觉创业五年了&#xff0c;也算一个屡战屡败、屡败屡战的创业老兵了。从第一次失败要靠吃抗抑郁的药&#xff0c;到现在理性的看待成败得失&#xff0c;不得不说&#xff0c;创业这条路对我还是有不小提…

C++实现具有[数组]相似特征的类DoubleSubscriptArray

#include <iostream> using namespace std;class DoubleSubscriptArray {public:DoubleSubscriptArray(int x, int y) {p new int *[x];//行 //申请行的空间for (int i 0; i < x; i) {p[i] new int [y];//每行的列申请空间}for (int i 0; i < x; i)for (int j …

Docker-HealthCheck指令探测ASP.NET Core容器健康状态

写在前面HealthCheck 不仅是对应用程序内运行情况、数据流通情况进行检查&#xff0c;还包括应用程序对外部服务或依赖资源的健康检查。健康检查通常是以暴露应用程序的HTTP端点的形式实施&#xff0c;可用于配置健康探测的的场景有 &#xff1a;容器或负载均衡器 探测应用状态…

ASP.NET Core分布式项目实战(课程介绍,MVP,瀑布与敏捷)--学习笔记

任务1&#xff1a;课程介绍课程目标&#xff1a;1、进一步理解 ASP.NET Core 授权认证框架、MVC 管道2、掌握 Oauth2&#xff0c;结合 Identity Sercer4 实现 OAuth2 和 OpenID Connect Server3、掌握 ASP.NET Core 与 Redis, MongoDB, RabitMQ, MySQL 配合使用4、理解 DDD&…

html坐标轴背景色,CSS 背景(css background)

CSS 背景-CSS background一、Css background背景语法 - TOPCSS背景基础知识CSS 背景这里指通过CSS对对象设置背景属性&#xff0c;如通过CSS设置背景各种样式。背景语法&#xff1a;background: background-color || background-image || background-repeat || background-…

LeetCode 965单值二叉树-简单

如果二叉树每个节点都具有相同的值&#xff0c;那么该二叉树就是单值二叉树。 只有给定的树是单值二叉树时&#xff0c;才返回 true&#xff1b;否则返回 false。 示例 1&#xff1a; 输入&#xff1a;[1,1,1,1,1,null,1] 输出&#xff1a;true 示例 2&#xff1a; 输入&…

使用EF.Core将同一模型映射到多个表

在 EntityFramework Core 中&#xff0c;我们可以使用属性或Fluent API来配置模型映射。有一天&#xff0c;我遇到了一个新的需求&#xff0c;有一个系统每天会生成大量数据&#xff0c;每天生成一个新的表存储数据。例如&#xff0c;数据库如下所示&#xff1a;所有表都具有相…

EntityFramework Core 3.x添加查询提示(NOLOCK)

前几天看到有博客园中有园友写了一篇关于添加NOLOCK查询提示的博文&#xff0c;这里呢&#xff0c;我将介绍另外一种添加查询提示的方法&#xff0c;此方式源于我看过源码后的实现&#xff0c;孰好孰歹&#xff0c;请自行判之&#xff0c;接下来我们一起来看看。在EntityFramew…

Xamarin.Forms客户端第一版

1. 功能简介1.1. 读取手机基本信息主要使用Xamarin.Essentials库获取设备基本信息&#xff0c;Xam.Plugin.DeviceInfo插件获取App Id&#xff0c;其实该插件也能获取设备基本信息。1.2. 读取手机联系人信息Android和iOS工程具体实现联系人读取服务&#xff0c;使用到Dependency…

给 EF Core 查询增加 With NoLock

给 EF Core 查询增加 With NoLockIntroEF Core 在 3.x 版本中增加了 Interceptor&#xff0c;使得我们可以在发生低级别数据库操作时作为 EF Core 正常运行的一部分自动调用它们。例如&#xff0c;打开连接、提交事务或执行命令时。所以我们可以自定义一个 Interceptor 来记录执…

LeetCode 138 复制带随机指针的链表-中等

给你一个长度为 n 的链表&#xff0c;每个节点包含一个额外增加的随机指针 random &#xff0c;该指针可以指向链表中的任何节点或空节点。 构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成&#xff0c;其中每个新节点的值都设为其对应的原节点的值。新节点的 n…

ASP.NET Core分布式项目实战(业务介绍,架构设计,oAuth2,IdentityServer4)--学习笔记...

任务4&#xff1a;第一章计划与目录敏捷产品开发流程原型预览与业务介绍整体架构设计API 接口设计 / swaggerIdentity Server 4 搭建登录账号 API 实现配置中心任务5&#xff1a;业务介绍项目背景&#xff1a;基于人脉关系的金融行业项目用户&#xff1a;1、账号&#xff1a;基…

LeetCode 82 删除排序链表中的重复元素||-中等

存在一个按升序排列的链表&#xff0c;给你这个链表的头节点 head &#xff0c;请你删除链表中所有存在数字重复情况的节点&#xff0c;只保留原始链表中 没有重复出现 的数字。 返回同样按升序排列的结果链表。 输入&#xff1a;head [1,2,3,3,4,4,5] 输出&#xff1a;[1,2,…

你复工了吗?啥感受?

这里是Z哥的个人公众号每周五11&#xff1a;45 按时送达当然了&#xff0c;也会时不时加个餐&#xff5e;我的第「136」篇原创敬上感觉还没做什么事情&#xff0c;2020年的第一季度就结束了。相信大多数人也都已经复工了。之前进行远程公办的&#xff0c;大多也都回到了原先在公…

LeetCode 1669合并两个链表-中等

给你两个链表 list1 和 list2 &#xff0c;它们包含的元素分别为 n 个和 m 个。 请你将 list1 中第 a 个节点到第 b 个节点删除&#xff0c;并将list2 接在被删除节点的位置。 下图中蓝色边和节点展示了操作后的结果&#xff1a; 请你返回结果链表的头指针。 输入&#xff1a…