通用解决方案:Android 性能优化工具篇:如何使用 DDMS 中的 TraceView 工

优采云 发布时间: 2022-10-26 17:52

  通用解决方案:Android 性能优化工具篇:如何使用 DDMS 中的 TraceView 工

  前言

  Traceview是手机应用性能分析定位过程中使用最多的工具;启动时间较长、界面切换时间过长时首选工具;如果勾选了接口的帧率,建议先将GPU配置文件以列表的形式显示在屏幕上,这样就可以先查出是否是帧率有问题这个界面再做后续调查

  TraceView 定义

  TraceView 是 Android 平台特有的数据采集 和分析工具。主要用于分析Android中应用的热点;TraceView本身只是一个数据分析工具,数据采集需要使用Android SDK。调试类或使用 DDMS 工具

  两者的用法如下:

  TraceView 是如何使用的

  DDMS中TraceView的*敏*感*词*如下,调试器可以点击Devices中的应用,点击

  按钮 Start Method Profiling 并单击 Stop Method Profiling

  启用方法分析后,测试应用程序的目标页面。测试完成后,停止方法分析,界面会跳转到DDMS的trace分析界面。

  如下所示:

  TraceView界面比较复杂,它的UI分为两个面板,分别是Timeline Panel(时间线面板)和Profile Panel(分析面板);上图的上半部分是Timeline Panel(时间线面板),Timeline Panel也可以细分为左右Pane:

  上图的下半部分是Profile Panel(分析面板)。Profile Panel是TraceView的核心界面,内涵非常丰富;主要展示一个线程中每个函数调用的情况(先在Timeline Panel中选择线程)。,包括CPU使用时间、调用次数等信息。而这些信息是寻找热点的关键依据

  因此,对于开发者来说,一定要了解 Profile Panel 中每一列的含义;下表列出了 Profile Panel 中比较重要的列名和描述

  TraceView 在行动

  了解了 TraceView 的 UI 之后,就到了介绍如何使用 TraceView 查找热点的时候了。一般来说,热点包括两种类型的功能:

  测试背景

  APP在测试机上运行一段时间后,手机发热、死机、CPU占用率高。应用程序被切入后台监控CPU数据。结果表明,即使应用程序不执行任何操作,应用程序的 CPU 使用率也会不断增加。

  TraceView结果界面显示后,进行数据分析。在 Profile Panel 中,选择 Cpu Time/Call 降序排序(从上到下排列,每一项的时间消耗从高到低),得到如图所示的结果:

  验证码

  大致可以判断是ImageLoaderTools$2.run()方法有问题。在下面找到这个方法来验证代码:

   1 package com.sunzn.app.utils;

2

3 import java.io.File;

4 import java.io.IOException;

5 import java.io.InputStream;

6 import java.lang.ref.SoftReference;

7 import java.util.ArrayList;

8 import java.util.HashMap;

9

10 import android.content.Context;

11 import android.graphics.Bitmap;

12 import android.os.Environment;

13 import android.os.Handler;

14 import android.os.Message;

15

16 public class ImageLoaderTools {

17

18 private HttpTools httptool;

19

20 private Context mContext;

21

22 private boolean isLoop = true;

23

24 private HashMap mHashMap_caches;

25

26 private ArrayList maArrayList_taskQueue;

27

28 private Handler mHandler = new Handler() {

29 public void handleMessage(android.os.Message msg) {

30 ImageLoadTask loadTask = (ImageLoadTask) msg.obj;

31 loadTask.callback.imageloaded(loadTask.path, loadTask.bitmap);

32 };

33 };

34

35 private Thread mThread = new Thread() {

36

37 public void run() {

38

39 while (isLoop) {

40

41 while (maArrayList_taskQueue.size() > 0) {

42

43 try {

44 ImageLoadTask task = maArrayList_taskQueue.remove(0);

45

46 if (Constant.LOADPICTYPE == 1) {

47 byte[] bytes = httptool.getByte(task.path, null, HttpTools.METHOD_GET);

48 task.bitmap = BitMapTools.getBitmap(bytes, 40, 40);

49 } else if (Constant.LOADPICTYPE == 2) {

50 InputStream in = httptool.getStream(task.path, null, HttpTools.METHOD_GET);

51 task.bitmap = BitMapTools.getBitmap(in, 1);

52 }

53

54 if (task.bitmap != null) {

55 mHashMap_caches.put(task.path, new SoftReference(task.bitmap));

56 File dir = mContext.getExternalFilesDir(Environment.DIRECTORY_PICTURES);

57 if (!dir.exists()) {

58 dir.mkdirs();

59 }

60 String[] path = task.path.split("/");

61 String filename = path[path.length - 1];

62 File file = new File(dir, filename);

63 BitMapTools.saveBitmap(file.getAbsolutePath(), task.bitmap);

<p>

64 Message msg = Message.obtain();

65 msg.obj = task;

66 mHandler.sendMessage(msg);

67 }

68 } catch (IOException e) {

69 e.printStackTrace();

70 } catch (Exception e) {

71 e.printStackTrace();

72 }

73

74 synchronized (this) {

75 try {

76 wait();

77 } catch (InterruptedException e) {

78 e.printStackTrace();

79 }

80 }

81

82 }

83

84 }

85

86 };

87

88 };

89

90 public ImageLoaderTools(Context context) {

91 this.mContext = context;

92 httptool = new HttpTools(context);

93 mHashMap_caches = new HashMap();

94 maArrayList_taskQueue = new ArrayList();

95 mThread.start();

96 }

97

98 private class ImageLoadTask {

99 String path;

100 Bitmap bitmap;

101 Callback callback;

102 }

103

104 public interface Callback {

105 void imageloaded(String path, Bitmap bitmap);

106 }

107

108 public void quit() {

109 isLoop = false;

110 }

111

112 public Bitmap imageLoad(String path, Callback callback) {

113 Bitmap bitmap = null;

114 String[] path1 = path.split("/");

115 String filename = path1[path1.length - 1];

116

117 if (mHashMap_caches.containsKey(path)) {

118 bitmap = mHashMap_caches.get(path).get();

119 if (bitmap == null) {

120 mHashMap_caches.remove(path);

121 } else {

122 return bitmap;

123 }

124 }

125

126 File dir = mContext.getExternalFilesDir(Environment.DIRECTORY_PICTURES);

127

128 File file = new File(dir, filename);

129

130 bitmap = BitMapTools.getBitMap(file.getAbsolutePath());

131 if (bitmap != null) {

132 return bitmap;

133 }

134

135 ImageLoadTask task = new ImageLoadTask();

136 task.path = path;

137 task.callback = callback;

138 maArrayList_taskQueue.add(task);

139

140 synchronized (mThread) {

141 mThread.notify();

142 }

143

144 return null;

145 }

146

147 }

</p>

  以上代码就是ImageLoaderTools图片工具类的全部代码。不急着研究这个类的代码实现过程。我们先看看这个类是怎么调用的:

   1 ImageLoaderTools imageLoaderTools = imageLoaderTools = new ImageLoaderTools(this);

2

<p>

3 Bitmap bitmap = imageLoaderTools.imageLoad(picpath, new Callback() {

4

5 @Override

6 public void imageloaded(String picPath, Bitmap bitmap) {

7 if (bitmap == null) {

8 imageView.setImageResource(R.drawable.default);

9 } else {

10 imageView.setImageBitmap(bitmap);

11 }

12 }

13 });

14

15 if (bitmap == null) {

16 imageView.setImageResource(R.drawable.fengmianmoren);

17 } else {

18 imageView.setImageBitmap(bitmap);

19 }

</p>

  调用 ImageLoaderTools 的过程非常简单:

  在实例化ImageLoaderTools类的构造函数(第90-96行)的过程中,完成了网络工具HttpTools的初始化、新建图片缓存Map、创建下载队列、开启下载线程等工作。

  这时候请注意开线程的操作。打开线程后,执行run()方法(35-88行)。此时isLoop的值为默认true,maArrayList_taskQueue.size()为0。在任务队列中maArrayList_taskQueue这个循环会一直持续到没有添加下载任务

  在执行imageLoad()方法加载图片时,会先去缓存mHashMap_caches查看图片是否已经下载。如果已经下载,则直接返回对应的位图资源。如果没有找到,就会在maArrayList_taskQueue中添加一个下载任务,并唤醒对应的下载线程。之前打开的线程发现maArrayList_taskQueue.size() &gt; 0后进入下载逻辑。下载任务完成后,将对应的图片资源添加到缓存mHashMap_caches,更新UI。下载线程执行挂起的wait()方法

  一张图片下载的业务逻辑,这样就很容易理解了,好像也没什么问题。一开始我也是这么想的,但是后来在仔细分析代码的过程中发现,如果重新加载同一个图片资源,就会出现死循环

  还记得缓存 mHashMap_caches 吗?

  死循环才是手机发热、卡死、CPU占用率高的真正原因

  解决方案

  准确定位代码问题后,提出解决方案就很简单了。这里提供的解决方案是将wait()方法从内层while循环移到外层while循环,这样当同一张图片重复加载时就会死掉。线程一出现循环就挂起,这样就可以避免出现死循环。代码显示如下:

   1 private Thread mThread = new Thread() {

2

3 public void run() {

4

5 while (isLoop) {

6

7 while (maArrayList_taskQueue.size() > 0) {

8

9 try {

10 ImageLoadTask task = maArrayList_taskQueue.remove(0);

11

12 if (Constant.LOADPICTYPE == 1) {

13 byte[] bytes = httptool.getByte(task.path, null, HttpTools.METHOD_GET);

14 task.bitmap = BitMapTools.getBitmap(bytes, 40, 40);

15 } else if (Constant.LOADPICTYPE == 2) {

16 InputStream in = httptool.getStream(task.path, null, HttpTools.METHOD_GET);

17 task.bitmap = BitMapTools.getBitmap(in, 1);

18 }

19

20 if (task.bitmap != null) {

21 mHashMap_caches.put(task.path, new SoftReference(task.bitmap));

22 File dir = mContext.getExternalFilesDir(Environment.DIRECTORY_PICTURES);

23 if (!dir.exists()) {

24 dir.mkdirs();

25 }

26 String[] path = task.path.split("/");

27 String filename = path[path.length - 1];

28 File file = new File(dir, filename);

29 BitMapTools.saveBitmap(file.getAbsolutePath(), task.bitmap);

30 Message msg = Message.obtain();

31 msg.obj = task;

32 mHandler.sendMessage(msg);

33 }

34 } catch (IOException e) {

35 e.printStackTrace();

36 } catch (Exception e) {

37 e.printStackTrace();

38 }

39

40 }

41

42 synchronized (this) {

43 try {

44 wait();

45 } catch (InterruptedException e) {

46 e.printStackTrace();

47 }

48 }

49

50 }

51

52 };

53

54 };

  最后附上代码修改后运行的代码性能图,之前的执行已经重复了很多次。效率有了质的提升,手机过热、死机、CPU占用率高的现象也消失了。

  总结

  文章 中提到的功能只是列举了 TraceView 工具的部分用法。需要文中完整代码或者更多Android相关学习资料的可以这样做;点此查看获取方法或私信“Android进阶”,可以获得一系列Android技术学习手册;希望这本手册能给大家学习Android带来一些帮助

  操作方法:网站TDK采集工具-网站的TDK设置方法

  网站 的 TDK 是什么?TDK是网站的标题、描述和关键词(关键字),TDK是网站的一个很重要的元素,它是蜘蛛爬你的网站第一眼看到的之后,所以设置TDK对网站的优化很关键。如何设置 网站 的 TDK?今天给大家分享一个批处理行业的网站TDK采集工具,分析网站TDK的排名如何,从而更好的搭建自己的网站TDK ,详细参考下图

  要做网站优化,首先要学会诊断网站问题,从基本的网站TDK(title,deion,keywords)到网站代码,框架,内部链接,外部链接、锚文本、404、301等。我们不应该说我们应该精通,至少我们应该知道什么可以做,什么不能做。

  一个公司成立后网站,离不开网站的优化和推广。SEO优化是企业获得良好排名的有效手段。那么,企业网站的优化方案是什么?如何规划?

  定位包括:用户群体定位、推广渠道定位、差异化定位、网站风格定位等,其中最重要的是用户群体定位和差异化定位。如果这两个定位正确,产品基本上就成功了一半。定位时,我们会使用思维导图模型来分析用户群有多大?商业模式解读!推广渠道示例!同行研究!我们将推导出商旅的差异化卖点。基于用户体验,我们将比同行做得更好。

  了解我们的同行是网站规划中的重要一步。只有知己知彼,才能百战百胜。了解其网站物理结构、URL结构、关键词布局、现有收录和排名必须合理。

  

  根据同行的定位和理解,核心关键词基本可以确定。关键词 的确定至关重要。core关键字是整个网站关键字系统的核心,不能容忍任何错误。一般来说,关键词也是难度和流量的关键词。

  1. 频繁的站点TDK变更

  一段时间后,SEO优化的朋友一般不会犯这样的错误。基本上,一些新手经常会犯这样的错误。频繁的网站标题改动危害很大,因为一个搜索引擎改动会再次被审查,增加了搜索引擎的解读成本,尤其是新的网站还在百度审核期,如果不被看好通过搜索引擎,百度很可能不会收录你的网站。所以如果你的 网站 不是很重要,不要只是改变标题。

  2.关键词布局的选择不合理

  众所周知,搜索引擎要求全站主要关键词的布局密度占全站内容的2%~8%。无论您选择什么关键词,密度都必须达到标准。其次,关键词的选择很重要。比如你是一个新站,你觉得你能做一个索引为5000的词吗?当然,这样的选择是不合理的,词语的选择需要根据自己的需要和实际情况。在选择关键词的时候,应该选择一些容易优化和用户关心的词。记住关键词不容易过热或过冷,过热容易优化,过冷不带来流量。此外,应避免使用 关键词。

  

  网站优化没有统一的标准,更何况可以参考相同的案例,其中收录太多不确定因素,所以在网站优化的过程中,使用相同的方法两个不同的网站优化,结果可能会有所不同。虽然我们无法控制优化过程中的每一个因素,但通过一些更科学的方法,可以使优化结果朝着预定的方向发展。

  一般来说,关于如何优化网站,我们建议你可以将网站的优化分成几个阶段,分阶段完成,这样可以让整个优化工作更加有序和快速。

  如何优化网站:分析

  在网站优化开始之前,应该详细分析市场和目标用户。否则,核心关键词和长尾关键词从何而来?网站的栏目和内容如何排列?在这个过程中不要仅仅依靠直觉。凭直觉选择的 关键词 通常最终会变得不可靠。当然,关键词 指数的分析在某些行业是不可靠的。正确的方法应该是整合各方数据,一般来自索引查询、关键词挖掘工具、搜索引擎下拉框、搜索引擎相关搜索、竞争对手网站等渠道,并将它们组合在一起。自己的能力和网站特性确定优化方案网站的方法和关键词。

  如何优化网站:执行

  没有必要引入过多的行政权力。我相信每个人都能明白真相。计划再好,也是一张废纸。

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线