Debugging Android Apps
In this chapter, you will find out what to do when apps get buggy. You will learn how to use LogCat, Android Lint, and the debugger that comes with Eclipse.
To practice debugging, the first step is to break something. In QuizActivity.java, comment out the code in onCreate(Bundle) where you pull out mQuestionTextView.
Run GeoQuiz and see what happens.Figure 1.1 GeoQuiz is about to E.X.P.L.O.D.E.
Figure 1-1 the app crashes and burns
Figure 1.1 shows shows the message that appears when your app crashes and burns. Different versions of Android will have slightly different messages, but they all mean the same thing. Of course, you know what is wrong with your app, but if you did not, it might help to look at your app from a new perspective.
1.The DDMS Perspective
From the Eclipse menu, select Window→ Open P erspective → DDMS.
A perspective is a pre-defined set of views in Eclipse. You usually want to see different views when you are debugging than when you are editing, so Eclipse puts each set of views together into a perspective.
Perspectives are pre-defined, but they are not set in stone. You can add and remove views from any of them, and Eclipse will remember your choices. If you ever need to start fresh, you can return a perspective to its default state by choosing Window→ Reset Perspective...
The default perspective where you have been editing code is called the Java perspective. The perspectives that you currently have open are listed near the top-right of the Eclipse workbench, and you can click on those buttons to switch between them.
DDMS stands for Dalvik Debug Monitor Service. Behind the scenes, DDMS does the footwork for all Android debugging. The DDMS perspective includes LogCat and the Devices view.
The Devices view shows you which devices and virtual devices are connected to your computer. Problems you are having with a specific device can usually be solved in this view.
For example, is your device not showing up as an option when you run an application? Click the downward-pointing triangle at the top-right corner and select Reset adb. Often, rebooting adb will find your device. Or is LogCat showing output for the wrong device? No problem – click to select the device you want to see output from, and LogCat will switch to showing output from that device.
2.Exceptions and Stack Traces
Now back to your app rsquo;s problem. Expand the LogCat pane so that you can see what has happened. If you scroll up and down in LogCat, you should eventually find an expanse of red. This is a standard AndroidRuntime exception report.Figure 2-1 Exception and stack trace in LogCat。
Figuer2-1 Exception and stack trace in LogCat
The report tells you the top-level exception and its stack trace, then the exception that caused that exception and its stack trace, and so on and so forth until it finds an exception with no cause.
In most of the code you will write, that last exception with no cause is the interesting one. Here the exception without a cause is a java.lang.NullPointerException. The line just below this exception is the first line in its stack trace. This line tells
you the class and method where the exception occurred as well as what file and line number the exception occurred on.Double-click this line, and Eclipse will take you to that line in your source code.
The line to which you are taken is the first use of the mQuestionTextView variable, inside updateQuestion(). The name NullPointerException gives you a hint to the problem: this variable was not initialized.
Uncomment the line initializing mQuestionTextView to fix the bug.
When you run into runtime exceptions, remember to look for the last exception in LogCat and the first line in its stack trace that refers to code that you have written. That is where the problem occurs, and it is the best place to start looking for answers.
If a crash occurs on a device while it is not plugged in, all is not lost. The device will store the latest lines written to the log.The length and expiration of the stored log depends on the device, but you can usually count on retrieving log results within
ten minutes. Just plug in the device, pull up DDM S in Eclipse, and select your device in the Devices view. LogCat will fill itself with the stored log.
2.1 Diagnosing misbehaviors
Problems with your apps will not always be crashes. In some cases, they will be misbehaviors. For example, suppose that every time you pressed the Next button, nothing happened. That would be a non-crashing, misbehaving bug.
In QuizActivity.java, make a change to the mNextButton listener to comment out the code that increments mCurrentIndex.
Run GeoQuiz and press the Next button. You should see no effect.
This bug is trickier than the last bug. It is not throwing an exception, so fixing the bug is not a simple matter of making the exception go away. On top of that, this misbehavior could be caused in two different ways: the index might not be changing, or updateQuestion() might not be called.
If you had no idea what was causing the problem, you would need to track down the culprit. In the next few sections, you will see two ways to do this: diagnostic logging of a stack trace and using the debugger to set a breakpoint.
2.2 Logging stack traces
In QuizActivity, add a log statement to updateQuestion().
The Log.d(String, String, Throwable) version of Log.d logs the entire stack trace just like with the AndroidRuntime exception you saw earlier. Th
剩余内容已隐藏,支付完成后下载完整资料
Android应用的调试
本章将学习如何处理应用bug。同时也会学习如何使用LogCat、Android Lint以及Eclipse内置的代码调试器。
为练习应用调试,我们先刻意搞点破坏。打开命名为QuizQuizActivity.java文件,在onCreate(Bundle)方法中,注释掉获取TextView组件并赋值给mQuestionTextView变量的那行代码。
运行GeoQuiz应用,看看会发生什么,如图1-1所示。
图 1-1 应用崩溃
图1-1展示了应用崩溃后的消息提示画面。不同Android版本的消息提示可能略有不同,但本质上它们都是同一个意思。当然,这里我们知道应用为何崩溃。但假如不知道应用为何出现异常,下面将要介绍的DDMS透视图或许有助于问题的排查。
1.DDMS 应用调试透视图
在Eclipse中,选择Window → Open Perspective → DDMS菜单项打开DDMS透视图。
透视图是Eclipse中预先定义的一组视图。应用调试或者代码编辑的时候,我们通常需要看到不同的视图组合。因此,Eclipse按照实际开发需要,将每组视图组合成了一幅透视图。
预定义的透视图并非不可改变。我们可以通过添加和移除视图来重新定制透视图,Eclispe会自动记住这些调整。如需重新开始调整,单击Window → Reset Perspective...菜单项返回透视图的初始状态即可。
代码编辑时使用的默认透视图叫Java透视图。当前打开的所有透视图都列在Eclipse工作区的右上角附近。点击对应透视图的按钮可实现透视图间的自由切换。
DDMS(Dalvik Debug Monitor Service,调试监控服务工具)在后台处理Android应用调试所需的全部底层工作。DDMS透视图主要包含了LogCat以及Devices视图。
Devices视图用来显示连接至电脑的Android硬件和虚拟设备。设备相关的各种问题通常都可以在该视图中得到解决。
比如说,运行应用时在Devices视图中找不到自己的设备?很容易解决,单击视图右上角向下的小三角图标,然后在弹出的菜单中选择Reset adb选项。一般来说,重启adb就可以找回所用设备。或者LogCat输出了其他设备的日志信息?没问题,在视图中点选当前工作的设备,LogCat会切换并显示该设备的日志输出。
2.异常与栈跟踪
现在回头来看应用崩溃的问题。为方便查看异常或错误信息,可展开LogCat窗口。上下滑动滚动条,最终应该会看到整片红色的异常或错误信息。这就是标准的Android运行时的异常信息报告,如图2-1所示。
图 2-1 LogCat的异常与栈追踪
该异常报告首先告诉了我们最高层级的异常及其栈追踪,然后是导致该异常的异常及其栈追踪。如此不断追溯,直到找到一个没有原因的异常。
在大部分编写的代码中,最后一个没有原因的异常往往是我们要关注的目标。这里,没有原因的异常是java.lang.NullPointerException。紧接着该异常语句下面的一行就是其栈追踪信息的第一行。从该行可以看出发生异常的类和方法以及它所在的源文件及代码行号。双击该行,Eclipse自动跳转到源代码的对应行上。
Eclipse 定 位 的 这 行 代 码 是 mQuestionTextView 变 量 在 onCreate() 方 法 中 的 首 次 使 用 。
NullPointerException名称的异常暗示了问题的所在,即变量没有进行初始化。
为修正该问题,取消对变量mQuestionTextView初始化语句的注释。
遇到运行异常时,记住在LogCat中寻找最后一个异常及其栈追踪的第一行(该行对应着源代码)。这里是问题发生的地方,也是寻找问题答案的最佳起始点。
如果发生应用崩溃的设备没有连接到电脑上,日志信息也不会全部丢失。设备会将最近的日志信息保存到log文件中。日志文件的内容长度及保留的时间取决于具体的设备,不过,获取十分钟之内产生的日志信息通常是有保证的。只要将设备连上电脑,打开Eclipse的DDMS透视图,在Devices视图里选择所用设备。LogCat将自动打开并显示日志文件保存的日志信息。
2.1 诊断应用异常
应用出错不一定总会导致应用崩溃。某些时候,应用只是出现了运行异常。例如,每次单击Next按钮时,应用都毫无反应。这就是一个非崩溃型的应用运行异常。
在QuizActivity.java中,修改mNextButton监听器代码,将mCurrentIndex变量递增的语句注释掉。
运行GeoQuiz应用,点击Next按钮。可以看到,应用毫无响应。
这个问题要比上个更为棘手。它没有抛出异常,所以修正这个问题不像前面跟踪追溯并消除异常那么简单。有了解决上个问题的经验,这里可以推测出导致该问题的两种可能因素:
mCurrentIndex变量值没有改变;
updateQuestion()方法没有调用成功。
如不知道问题产生的原因,则需要设法跟踪并找出问题所在。在接下来的几小节里,我们将学习到两种跟踪问题的方法:
记录栈跟踪的诊断性日志;
利用调试器设置断点调试。
2.2 记录栈跟踪日志
在QuizActivity中,为updateQuestion()方法添加日志输出语句。
如同前面AndroidRuntime的异常,Log.d(String, String, Throwable)方法记录并输出整个栈跟踪信息。借助栈跟踪日志,可以很容易看出updateQuestion()方法在哪些地方被调用了。
作为参数传入 Log.d(...)方法的异常不一定是我们捕获的已抛出异常。创建一个新的Exception()方法,把它作为不抛出的异常对象传入该方法也是可以的。借此,我们得到异常发生位置的记录报告。
运行GeoQuiz应用,点击Next按钮,然后在LogCat中查看日志输出。
栈跟踪日志的第一行即调用异常记录方法的地方。紧接着的两行表明,updateQuestion()方法是在onClick(...)实现方法里被调用的。双击该行即可跳转至注释掉的问题索引递增代码行。暂时保留该代码问题,下一节我们会使用设置断点调试的方法重新查找该问题。
记录栈跟踪日志虽然是个强大的工具,但也存在缺陷。比如,大量的日志输出很容易导致LogCat窗口信息混乱难读。此外,通过阅读详细直白的栈跟踪日志并分析代码意图,竞争对手可以轻易剽窃我们的创意。
另一方面 ,既然有时 可以从栈跟 踪日志看出 代码的实际 使用意图, 在网站 http://stacko-verflow.com或者论坛http://forums.bignerdranch.com上寻求帮助时,附上一段栈跟踪日志往往有助于更快地解决问题。根据需要,我们既可以直接从LogCat中复制并粘贴日志内容,也可以选中要保存的内容,单击LogCat右上角的小软盘图标将它们保存到文本文件中。
在继续学习之前,先注释掉QuizActivity.java中的TAG常量,然后删除日志记录代码。
注释掉TAG常量会移除未使用的变量警告。当然,也可以删除TAG常量,但最好不要这样做。因为,保不准什么时候还会用它来记录日志消息。
2.3 设置断点
要 使 用 Eclispe 自 带 的 代 码 调 试 器 跟 踪 调 试 上 一 节 中 我 们 遇 到 的 问 题 , 首 先 需 要 在
updateQuestion()方法中设置断点,以确认该方法是否被调用。断点会在断点设置行的前一行代码处停止运行,然后我们可以逐行检查代码,看看接下来到底发生了什么。
在QuizActivity.java文件的updateQuestion()方法中,双击第一行代码左边的灰色栏区域。可以看到,灰色栏上出现了一个蓝色圈圈。这就是我们设置的一处断点。
启用代码调试器并触发已设置的断点,我们需要调试运行而不是直接运行应用。要调试运行应用,右键单击GeoQuiz项目,选择Debug As → Android Application菜单项。设备会报告说正在等待调试器加载,然后继续运行。
应用启动并加载调试器运行后,应用将会暂停。应用首先调用QuizActivity.onCreate(Bundle)方法,接着调用updateQuestion()方法,然后触发断点。
若是首次使用调试器,会看到询问是否打开调试透视图的提示窗口弹出。单击Yes按钮确认。
Eclipse 随 后 打 开 了 代 码 调 试 透 视 图 。 调 试 透 视 图 中 间 部 分 是 代 码 编 辑 视 图 。 可 以 看 到
QuizActivity.java代码已经在其中打开了,断点设置所在行的代码也被加亮显示了。应用在断点处停止了运行。
代码编辑视图上方是代码调试视图,如图4-8所示。该视图显示了当前的栈。
可使用视图顶部的黄色箭头按钮单步执行应用代码。从栈列表可以看出updateQuestion()方法已经在onCreate(Bundle)方法中被调用了。不过,我们需要关心的是检查Next按钮被点击后的行为。因此单击Resume按钮让程序继续运行。然后,再次点击Next按钮观察断点是否被激活(应该被激活)。
既然可以重复断点暂停然后再Resume的过程,也就可以趁机了解下调试透视图中的其他视图。右上方是变量视图。程序中各对象的值都可以在该视图中观察到。该视图首次出现时,只能看到this的值(QuizActivity本身)。单击this旁边的三角展开按钮或点击右箭头键可看到全部变量值。
变量名旁边的彩色图形表明了该变量的可见性:
绿色圆圈 公共变量;
蓝色三角 默认变量(包内可见);
黄色菱形 保护变量;
红色正方形 私有变量。
展开this变量后出现的变量数量之多有点让人吃惊。除QuizActivity类中实例变量外,它的Activity超类、Activity超类的超类(一直追溯到继承树的顶端)的全部变量也都列在了this下面。
我们现在只需关心变量mCurrentIndex的值。在变量视图里滚动查看直到找到mCurrent-Index。显然,它现在的值为0。
代码看上去没问题。为继续追查,需跳出当前方法。单击Step Over按钮右边的Step Return按钮(为跳过助手方法access$1(QuizActivity),因此我们要单击Step Return按钮两次)。
查看代码编辑视图,我们现在跳到了mNextButton的OnClickListener方法,正好是在updateQuestion()方法被调用之后。真是相当方便的调试,问题解决了。
接下来我们来修复代码问题。不过,在修改代码前,必须先停止调试应用。停止调试有两种方式:
停止程序,选中DDMS设备视图中的程序运行进程,单击红色的停止按钮杀掉进程。
断开调试器,在视调试图直接单击Disconnect按钮即可,如图4-8所示。
断开调试器要比停止程序更简单些。
然后切换到Java透视图,在OnClickListener方法中取消对mCurrentIndex语句的注释。
代码修复后,记得清除断点设置。选中变量视图旁的断点视图。(如看不到断点视图,可选择Window → Show View → Breakpoints菜单项打开)在断点视图中选择断点,单击视图上方的深灰色X按钮完成清除。
至此,我们已经尝试了两种不同的代码跟踪调试方法:
记录栈跟踪诊断性日志;
利用调试器设置断点调试。
没有哪种方法更好些,它们各有所长。通过实际应用中的比较,也许我们会有自己的偏爱。
栈跟踪记录的优点是,在同一日志记录中可以看到多处的栈跟踪信息;缺点是,必须学习如何添加日志记录方法,重新编译、运行并跟踪排查应用问题。相对而言,代码调试的方法更为方便。以调试模式运行应用后(选择Debug As → Android Application菜单项),可在应用运行的同时,在不同的地方设置断点,寻找解决问题的线索。
2.4 使用异常断点
如一时无法设置合适的断点,我们仍然可以使用调试器来捕捉异常。在QuizActivity.java中,再次注释掉mQuestionTextView变量的赋值语句。选择Run → Add Java Exception Breakpoint...
菜单项调出异常断点设置窗口。
通过该对话窗口设置所需的异常断点。这样,无论任何时候,只要应用抛出异常就可以触发该断点。根据需要,可
剩余内容已隐藏,支付完成后下载完整资料
资料编号:[147282],资料为PDF文档或Word文档,PDF文档可免费转换为Word
以上是毕业论文外文翻译,课题毕业论文、任务书、文献综述、开题报告、程序设计、图纸设计等资料可联系客服协助查找。