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…

LeetCode 226翻转二叉树-简单

翻转一棵二叉树。 示例&#xff1a; 输入&#xff1a; 4/ \2 7/ \ / \ 1 3 6 9输出&#xff1a; 4/ \7 2/ \ / \ 9 6 3 1代码如下: /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode…

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;但这是一个很好的学习和练习。它涉及到框架的一些“核心”部分。…

LeetCode 404左叶子之和-简单

计算给定二叉树的所有左叶子之和。 示例&#xff1a; 3/ \9 20/ \15 7在这个二叉树中&#xff0c;有两个左叶子&#xff0c;分别是 9 和 15&#xff0c;所以返回 24 代码如下: /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode…

android apt最新版本,解决Android studio 2.3升级到Android studio 3.0 后apt报错问题

解决Android studio 2.3升级到Android studio 3.0 后apt报错问题发布时间&#xff1a;2020-09-16 19:59:42来源&#xff1a;脚本之家阅读&#xff1a;62作者&#xff1a;哈特中尉1.现象描述原来项目在Android studio 2.3一切正常&#xff0c;升级3.0之后报如下错误&#xff1a;…

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

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

android中弹出窗口,如何在Android中创建弹出窗口(PopupWindow)

如何制作一个简单的Android弹出窗口这是一个更完整的例子。这是一个补充性答案&#xff0c;涉及一般情况下创建弹出窗口的过程&#xff0c;而不一定是OP问题的具体细节。(OP要求取消按钮&#xff0c;但这不是必需的&#xff0c;因为用户可以在屏幕上的任意位置单击以将其取消。…

LeetCode 04检查平衡性-简单

实现一个函数&#xff0c;检查二叉树是否平衡。在这个问题中&#xff0c;平衡树的定义如下&#xff1a;任意一个节点&#xff0c;其两棵子树的高度差不超过 1。 示例 1: 给定二叉树 [3,9,20,null,null,15,7] 3/ \9 20/ \15 7返回 true 。 示例 2: 给定二叉树 [1,2,2,3,…

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

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

C++ using namespace 命名空间的定义与使用

#include <iostream> using namespace std;namespace A {int x, y;void fun() {cout << "hello world" << endl;} }int main() {using namespace A;cout << x << endl;fun();return 0; }

android webview framework,android – Webview导致ANR

我编写了一个应用程序,它在Webview中显示html页面,这些页面在ViewPager中管理.一切正常,但是从一页翻到另一页时我有几个ANR. ANR数据转储显示主线程已通过ThreadedRenderer.nSyncAndDrawFrame()调用它调用本机方法,该方法显然与Renderer线程通信,并等待该线程完成绘制视图.由于…

创业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;容器或负载均衡器 探测应用状态…

LeetCode28 对称的二叉树-简单

请实现一个函数&#xff0c;用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样&#xff0c;那么它是对称的。 例如&#xff0c;二叉树 [1,2,2,3,4,4,3] 是对称的。 1/ \2 2/ \ / \ 3 4 4 3但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的: 1/ \2 2\ …

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;所有表都具有相…