本文概述
- Android中的DDMS:我的自省武器
- Android Studio中的DDMS快速指南
- 线程信息控制台:简化Android CPU使用率
- 网络统计控制台
- Android DDMS中的设备状态仿真
- 调试Android:每周一个小时不一样!
发展是一项棘手的事情。目标不断发展, 新技术和新领域不断出现, 新工具时不时弹出, 并且语言在似乎可以管理的混乱中发生了变化。
即使进行了所有这些更改, 基本规则仍保持不变。这些基本规则中最重要的一项规定, 要创建真正出色的软件, 你必须对执行系统进行深入, 持续和详细的自省。诊断, 调试和性能分析是有时在此上下文中使用的术语, 但是规则更加深入。一流的开发人员从字面上”感觉”到他的系统。他知道导致阻塞的原因是等待更多的内存释放, 导致线程陷入CPU饥饿状态, 这些动作将导致大量的I / O或网络访问, 从而减慢其整体运行速度。
真的没有办法解决。你可能是一个非常聪明的开发人员, 编写了很棒的代码, 但是, 除非你没有上述技能, 即能够监控和研究系统运行时行为的详细信息, 否则在交付真正一流的软件时仍然会失败应用程序。
实际上, 在获得一些经验之后, 你将检测到整个类别的”代码疾病”, 这可以追溯到忽略自省规则:简而言之, 编写代码(有时是智能代码)时无需连续监视其对实际平台的影响。
Android中的DDMS:我的自省武器
对我们来说幸运的是, Android社区已经成功提供了许多一流的自省工具。 Facebook的Stetho是最好的, 而AT&T的ARO(“应用程序资源优化器”)虽然年代稍长, 但仍然是顶尖的, 可能是最好的网络监控控制台, 而LeakCanary则采取了一种更加有限的方法来集中精力(并且在它)在运行时内存泄漏检测库上。长话短说, 那里不乏Android调试工具。
仍然是皇冠上的钻石, 它是自检工具, 可在需要提取有关应用程序运行时行为的关键, 准确和格式正确的数据时信任它, 它仍然是Android Studio中的老版本Dalvik Debug Monitor Server(DDMS), 自从Eclipse Android插件问世以来, 我们就一直与我们在一起(很多团队都没有很好地使用ala)。
DDMS在Android开发中有多重要?好吧, 如果知道我现在对DDMS和移动应用程序监视的了解, 一般说来5到6年前, 作为一个经验不足的Android开发人员, 我将省去很多头痛和调试工作。
事实是, DDMS非常容易掌握!
当然, 与其他任何软件工具一样, 正确使用它的很大一部分都来自经验。你需要磨练一段时间的专业技能, 直到你真正擅长于运行时性能监视为止。但是即使在几个小时内, 阅读本文后也要说, 如果你遵循我的建议并将其应用于下一个应用程序, 结果将是惊人的!对复杂的系统进行性能分析和调整并不难。这也可能很有趣!
人们经常会问一个问题, 那就是新手和开发人员之间的区别。精通Android的DDMS(或概括地说, 应用程序配置文件和自检功能)就是这样的主要区别之一。
注意:成为顶尖开发人员的主要部分是使用你域中可用的最佳库。在先前的srcmini文章中, 我列出了一些可用于Android的最佳开发人员库。从某种意义上讲, 本文是”库”文章的续篇, 涵盖了许多Android工具之一。不用说, 如果你打算提高自己的Android开发人员技能, 请立即阅读!
Android Studio中的DDMS快速指南
现在, 不用多说, 现在让我们深入研究DDMS(最终的Android开发人员工具之一)的描述。
在权衡利弊的同时, 可能没有其他工具可以提高应用程序的质量, 并帮助你查找可能包含的真正混乱和难以捉摸的错误。但是仍然由于某种原因(懒惰, 有人吗?), 所以许多团队无法使用DDMS。
让我们从DDMS速成班开始:
可以通过Studio>工具> Android> Android设备监视器并单击菜单上的DDMS按钮来访问DDMS。你也可以将快捷方式图标放置在上面板中(我愿意)。
打开后, 你将看到:
左侧面板允许选择设备/应用程序, 右侧控制台为你提供多个视图, 每个视图都位于其自己的标签中, 每个视图均显示你的应用程序的特定视图。
Dalvik Debug Monitor Server提供的主要服务是:
- 应用程序内存使用情况统计信息(总堆和对象分配统计信息)
- 应用线程统计
- 设备屏幕截图
- 设备文件浏览器
- 来电和短信欺骗
- 位置数据欺骗
- Logcat
要获取你的应用程序使用的当前堆内存值, 只需执行以下操作:
- 连接运行你的应用程序的设备
- 单击更新堆按钮以启用堆统计信息收集
- 打开堆标签
- 单击”引起GC”以强制运行GC。只有这样运行之后, 堆数据收集才会开始
- 保持标签打开, 继续使用你的应用程序, 并定期重新单击” Cause GC”以刷新堆统计数据
最后一行可能需要其他说明。内存使用率是那些分析值之一, 其动态性比初始值重要得多。对于大多数应用程序, 我们不太在乎初始堆使用值。我们将非常关注这一价值的进展, 因为它将为我们提供一个清晰的迹象, 表明移动开发商正面临的真正噩梦-Android内存泄漏:
我对堆状态模块的使用很简单;作为开发应用程序生命周期的一部分, 在引入可能影响堆使用的更改之后, 我将激活模块” Cause GC”以启动统计信息收集, 激活(通常不止一次)我的应用程序的堆密集位置, 并定期”引起GC”进行刷新。如果堆使用量持续增长, 那么我手上就会发生内存泄漏, 我需要解决它(有关如何操作的详细信息, 请参见下文)。如果不是这样, 无论实际堆大小如何, 我都很好。
如果检测到内存泄漏, 则我将使用的下一个工具是对象分配跟踪器。让我们看看它可以在Android中进行内存管理。
对象分配跟踪器
简而言之, 分配跟踪器将为你提供所需的信息, 以找出谁是当前堆大小的”责任方”。该模块将实时告诉你分配命令来自哪个线程和方法, 这对于Android中的内存分析非常有用。
要开始跟踪, 请执行以下操作:
- 像以前一样选择相关的设备/过程
- 切换到”分配跟踪器”选项卡, 然后单击”开始跟踪”开始。
- 从这里开始, 将跟踪所有新分配
- 点击”获取分配”以获取所有最新分配的列表视图(自上次”开始”以来最新)
- 要找出谁是分配权限, 请单击列表中的特定行
现在, 以我自己的经验, 在你的应用程序上执行大量分配操作, 然后单击”获取分配”以查看分配计数器, 通常应该可以直接将你引导到泄漏点;有时, 当泄漏是非线性的(即不时发生)时, 或者当你的应用包含多个可能无法正常工作的泄漏时。在这种情况下, 我还没有遇到很多, 你将需要手动创建转储HPROF文件并对其进行分析。本文将不涉及内存分析和Android内存管理。看到这里一些线索。
线程信息控制台:简化Android CPU使用率
任何开发人员都知道, 执行逻辑的同步路径被分为多个线程, 每个线程组成应用程序中的一个串行执行流。从字面上看, 所有应用程序都使用多个执行线程。其中一些使用数十个。
使用线程时对潜在问题的全面检查超出了本文的范围。然后让我们集中讨论一个问题, 即线程饥饿, 这是你要访问线程信息控制台的主要问题。
在所有移动应用程序中, 不同的线程将争夺CPU时间。根本没有足够的这些去处。如果由于某种原因一个或多个线程无法获得所需的执行时间, 将会发生什么?通常是坏事。系统将不会按照你计划的那样运行, 这总是一个坏主意。造成此问题的潜在原因可能是:设置了较低的优先级;其他线程同时以过高的优先级执行自身设置;在同步监视器上花费了很长时间;等等。众所周知, 所有这些都很难通过代码审查来发现。
Android DDMS线程控制台可助你一臂之力!
进入线程视图时, 你会看到一个由线程记录组成的列表, 每个记录包含线程的名称和ID, 以及另外两个称为utime和stime的计数器。 Utime度量线程执行用户代码所花费的总时间(请考虑你的函数和第三方库), 而stime度量所花费在系统代码上的总时间(睡眠, 同步, 系统调用等)。尽管我可以想到大多数情况下会由stime计数器显示出来的问题, 但第一个问题-utime-对我们来说通常会更有趣。
好的, 我们正在运行我们的代码, 其中包括多个线程, 并且我们希望确保所有线程都获得其CPU时间份额。为此, 我们首先让我们的系统运行一段时间, 然后打开”线程”选项卡并开始寻找”特殊的” utime值。零肯定可以表示一个问题-线程实际上没有CPU时间, 也没有CPU使用率。但是过高的值可能表示同一问题的不同方面:即, 线程的优先级很高, 以至于导致其他线程饿死。
请注意, 对于一种类型的线程, 零或接近零的utime值并不表示实际问题。这些是I / O绑定的线程, 这些线程主要用于网络或磁盘(或数据库)访问。这些线程应将大部分时间用于等待数据到达或阻塞未决的系统调用, 这两个操作均不会增加utime计数器。了解你的线程!
提示:切勿使用线程的默认名称。它没有任何意义, 通常你将无法在DDMS视图中检测到它。相反, 无论何时创建线程或从线程池中获取线程, 都应通过为其分配一个不言自明的名称来开始进行交互。这将使你的生活比调试/分析系统更容易。我通常以应用程序的名称开头, 以便区分Android生成的线程和由我自己的代码生成的线程, 例如:MyApp-server-connector, MyApp-db-interactor等。
提示:线程的优先级(宽松地说)表示调度程序将授予它的CPU时间。分配给工作线程的优先级对于应用程序的整体性能和”流畅性”至关重要, 在许多情况下, 可能是流畅的快速行为与颠簸的慢速行为之间的区别。这里的规则很简单:Android分配的默认优先级为NORMAL = 5, 几乎始终不是你要使用的优先级。相反, 对于大多数工作线程, 你希望以较小的方式对总体CPU使用率产生影响。为此, 在线程启动时, 将其优先级设置为较小的值, 我通常使用priority = 3。
网络统计控制台
网络统计信息是关于允许你以合理的人类可读方式监视应用程序的传入和传出通信渠道。
网络图表中的y轴表示以KB /秒为单位的传输速度, 而x轴表示以秒为单位的经过时间。因此, 要快速估算出传输的大小, 请尝试估算相关尖峰的面积。一段时间后, 这变得相当容易。
请注意, 进入此控制台后, 你将需要单击上方的”启用”按钮以开始显示网络测量值。
在网络控制台发展到现在的水平之前, 开发人员通常不得不诉诸嗅探器应用程序(有些仍然这样做)来获取类似信息。
该控制台的优点在于, 它可以可视化一种主要的电池消耗行为-正在进行的小数据包通信。众所周知, 让你的应用耗尽电量的原因并不是它需要花费五分钟的密集网络, 而是长时间的短暂重复网络, 例如为了保持活动, 诊断或状态更新。
一旦检测到这种模式, 并且网络控制台的可视数据包显示变得如此简单, 请立即考虑进行批处理。我可以将多个小型变速器分批成一个大型变速器吗?此更改对电池的影响必定会将应用程序从电池消耗器转移到性能良好的类别中!
提示:切勿按原样将图像加载到内存中。这是等待发生的内存不足崩溃。而是执行按比例缩小的加载, 或者甚至更好的方法是, 使用第三方库为你管理按比例缩小。
尽管你很少使用此信息, 但请注意, DDMS依赖于Android调试桥(ADB)堆栈来将数据传回设备。如果DDMS无法显示你的应用, 或者在DDMS会话过程中停滞, 则最好的选择是打开控制台并键入:
adb devices
确保你的设备可通过ADB访问并获得授权。如果不是这种情况, 则在许多情况下, 重新启动本地ADB服务器应该可以解决问题:
adb kill-server
adb devices # restarts the adb server and displays all detected devices
如果仍然有问题, 并且你的应用已安装在物理设备上, 请尝试断开所有仿真器实例的连接。为什么?因为DDMS会将自身连接到物理设备设备和仿真器实例, 所以默认为后者。
现实生活中DDMS用法示例:应用程序停止(不会崩溃, 只是停止)。用户立即赶往附近的工作站, 连接到USB, 然后在线程视图中打开DDMS以查找线程堆栈»失败的线程»堆栈跟踪-在我的情况下, 由于同步死锁(一旦检测到, 可以通过切换轻松解决)。
提示:如果Android分配给你的应用程序的标准RAM内存不够用(例如, 需要大量媒体的应用程序), 请注意, 通过提高_largeHeap清单标志, 你可以在大多数设备上获得15-20%的额外内存: https://developer.android.com/guide/topics/manifest/application-element.html_
Android DDMS中的设备状态仿真
通常, 移动应用程序不是线性结构。取而代之的是, 他们部署感知策略, 使他们可以监视设备状态并对其做出反应。例如, 应用程序可以侦听来电或短信, 可以根据网络状态重新调整其状态, 还可以跟踪设备位置并对其做出反应。
后者的一个简单例子是GPS应用程序。我们大多数人都不开发此类应用程序(糟糕, 市场还不够大……), 但是在许多情况下, 我们仍然部署逻辑, 该逻辑取决于位置, 无论是用户当前位置的简单地图视图, 还是路线跟踪, 或位置敏感的数据显示。
对这种状态敏感条件的测试非常复杂, 有时比编写实际代码要复杂得多。如果你的物理设备带有SIM卡, 那么你当然可以发出和接听电话和SMS。更改设备的电话状态非常困难, 但仍然可以完成。测试位置更改可能会比较棘手, 尽管可以选择使用笔记本电脑在城镇中漫步…
但是仍然-我们将如何处理仿真器实例?我们如何测试它们的变化?
DDMS再次营救。 DDMS的强大但经常被忽视的功能之一是它能够将模拟事件发布(“欺骗”)到正在运行的仿真器实例中。 DDMS可以从特定号码向仿真器发出呼叫, 发送SMS, 更改电话状态数据等。
一旦进入仿真器, 所有这些欺骗事件将不再与”真实”事件区分开, 即好像由底层硬件传感器接收到的那样。具体来说, 你所有相关应用程序的接收器都将按照收到真实呼叫/ SMS消息时的激活方式进行激活。
激活电话状态和操作非常简单:
要测试你的应用程序是否存在网络连通性低的情况(你应该在任何以网络为中心的应用程序中使用), 请转到”电话状态”部分, 然后将速度和延迟值设置为所需的值。我通常都将GPRS值用作两者的一种有效方法, 以模拟低连接性, 但是可以随意设置自己的值。
要模拟电话或短信, 请转到”电话操作”部分, 设置始发电话号码, 如果需要, 添加文字信息, 然后开除。当你为来自国外的呼叫设置了专用的代码路由并希望按预算对其进行测试时, 此工具特别有效。
模拟新位置时, 事情变得更加有趣。
如果你的目标只是为仿真器实例设置新位置, 请选择”手动”, 设置所需的纬度/经度值, 然后单击”发送”。
但是, 如果你希望你的应用程序不通过设置固定位置, 而是通过预设的路线, 例如, 检查用户从一个城市到另一个城市旅行时的行为, 该怎么办?对于任何支持地图的应用程序以及其他对位置敏感的应用程序(按用户位置设置其数据窗口), 此类测试都具有巨大的价值。在这里, 你将希望看到以不同速度移动的位置将使显示的数据窗口保持最新。
为此, 我们将使用一种称为KML的特殊格式, 该格式是专门为与Google Earth一起使用而开发的, 它表示路线或路径, 作为空间中的一组连接点, 可以通过启用GPS的设备来表示。
GPX是DDMS支持的替代路径格式。出于所有实际目的, 当用于移动位置欺骗时, 这两个应视为可互换。
现在让我们逐步完成在仿真器中设置模拟路线的各个阶段。
- 创建一条路线。到目前为止, 最简单的方法是使用Google Maps Direction选项设置适当的起点和终点。
-
路线显示在地图上后, 转到地址行并复制URL
-
使用剪贴板中的URL, 转到GPS Visualizer, 将其粘贴到”提供URL”文本框中, 然后单击”转换”按钮:
然后单击以下载生成的GPX文件(名称有些混乱, 例如20170520030103-22192-data.gpx)
- 返回DDMS位置控制, 打开” GPX”标签, 单击”加载GPX”, 然后选择新下载的文件
- 完成了!现在, 你可以通过单击”后退”和”前进”按钮, 或单击”播放”按钮以设置的速度自动进入路线, 从而在不同的路线位置之间导航。
你无需创建自己的路线。大量路线可从OpenStreetMap等网站下载(请参见” GPS跟踪”部分)。
最后, 请注意, 与较旧的DDMS版本不同, 路由文件的加载很容易, 而较新的DDMS版本在加载特定的路由时可能需要反复试验。
例如, 似乎DDMS仅支持GPX 1.1。新的GPX版本可能需要进行一些手动调整。
此外, 不再支持GPX航点格式。而是使用GPX跟踪格式:
<trk>
<name />
<cmt />
<trkseg>
<trkpt lat="27.0512" lon="-80.4324">
<ele>0</ele>
<time>2017-02-02T08:01:41Z</time>
</trkpt>
</trkseg>
</trk>
调试Android:每周一个小时不一样!
理论足够多!现在该练习一下了。我建议, 假设你是一名Android开发人员, 那么从你的下一个项目开始, 你将每周仅花一个小时来通过DDMS对应用程序的性能进行自省。
它将为你提供的大量质量信息(即, 可用于立即改善应用状态的信息)会让你感到惊讶!
正如我与新手开发人员反复见证的那样, Android DDMS是一种可以大大提高开发人员功能的工具, 前提是它能够被熟练掌握和正确使用。一旦开发人员充分利用DDMS在Android开发中的全部潜力, 那么Android开发人员提供一流系统的能力将提高1-2级。因此, 拨出几个小时来充分利用DDMS听起来是一项明智的投资, 因为它可以大大提高Android的性能和效率。
成为聪明人之一。用它。