和你一起终身学习,这里是程序员 Android

本篇文章主要介绍 ​​Android​​ 开发中 应用Crash 部分知识点,通过阅读本篇文章,您将收获以下内容:



  1. Crash 简介
  2. 发现问题
  3. 诊断问题
  4. 分析Crash堆栈信息
  5. 复现Crash
  6. Memory异常模拟
  7. 网络异常模拟
  8. logcat 调试异常


1. Crash 简介

每当未处理的异常或信号抛出时,就会导致APP意外退出,Android应用就会崩溃。如果使用Java编写的应用程序抛出由Throwable类表示的未处理的异常无人处理,APP 就会崩溃。如果在执行过程中出现未处理的信号(例如SIGSEGV),则使用 Native-Code 编写的应用程序将崩溃。

当应用程序崩溃时,Android会终止该应用程序的进程并显示一个对话框,让用户知道该应用程序已停止,如图1所示。


应用程序无需在前台运行即可使其崩溃。任何应用程序组件,甚至诸如在后台运行的广播接收器或内容提供程序之类的组件,都可能导致应用程序崩溃。这些崩溃通常使用户感到困惑,因为他们没有正在使用您的应用程序。

如果您的应用程序崩溃,则可以使用此页面中的指导来诊断和解决问题。有关如何在使用Native Code 构建的应用程序中诊断崩溃的指南,请参阅分析诊断Native Crash。

2. 发现问题

您可能并不总是知道您的用户因您的应用程序而崩溃。如果您已经发布了应用程序,则Android vitals可帮助您了解问题。

Android vitals

当您的应用程序崩溃过多时 ,Android Vitals 体可以通过Play控制台提醒您,从而帮助提高应用程序的性能 。Android生命周期认为应用程序崩溃时过多:


  • 在每天的会话中至少发生1.09%的崩溃。
  • 在每天至少0.18%的时段内展示两次或多次崩溃。

一个日常的会话是指在使用你的应用程序的日子。有关Google Play如何收集Android Vitals 数据的信息,请参阅 Play控制台文档。

在得知您的应用程序崩溃过多之后,下一步就是对其进行诊断。

3. 诊断问题

解决崩溃可能很困难。但是,如果您可以确定崩溃的根本原因,则很可能可以找到解决方案。

在许多情况下,可能会导致应用程序崩溃。一些原因很明显,例如检查一个空值或空字符串,但另一些原因则更微妙,例如将无效的参数传递给API甚至复杂的多线程交互。

4. 分析Crash堆栈信息

解决崩溃的第一步是确定崩溃发生的地方。如果您使用的是Play Console或logcat工具的输出,则可以使用报告详细信息中可用的堆栈跟踪 。如果没有可用的堆栈跟踪,则应通过手动测试应用程序或联系受影响的用户来本地重现崩溃,并在使用logcat时重现该崩溃。

以下跟踪显示了示例应用程序崩溃的示例:

--------- beginning of crash
AndroidRuntime: FATAL EXCEPTION: main
Process: com.android.developer.crashsample, PID: 3686
java.lang.NullPointerException: crash sample
at com.android.developer.crashsample.MainActivity$1.onClick(MainActivity.java:27)
at android.view.View.performClick(View.java:6134)
at android.view.View$PerformClick.run(View.java:23965)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:156)
at android.app.ActivityThread.main(ActivityThread.java:6440)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:746)
--------- beginning of system

堆栈跟踪显示了两条信息,这些信息对于调试崩溃至关重要:


  • 引发的异常类型。
  • 您的代码中抛出异常的部分。

引发异常的类型通常是关于错误原因的非常有力的暗示。看它是否是一个IOException,一个 OutOfMemoryError,或别的东西,并找到有关异常类的文档。

类,方法,文件在抛出异常的源文件的行号显示在堆栈跟踪的第二行上。对于被调用的每个函数,另一行显示先前的调用位置(称为堆栈框架)。通过遍历堆栈并检查代码,您可能会发现传递错误值的位置。如果您的代码未出现在堆栈跟踪中,则可能是在某个地方将无效参数传递给了异步操作。您通常可以通过检查堆栈跟踪的每一行,找到您使用的任何API类并确认传递的参数正确并在允许的地方调用它来弄清楚发生了什么。

有关Native Crash 程序崩溃的更多信息,请参阅Native Crash 类型。

5. 复现Crash

仅通过启动模拟器或将设备连接到计算机,您可能无法完全重现该问题。开发环境倾向于具有更多资源,例如带宽,内存和存储。使用异常类型来确定稀缺资源可能是什么,或者在Android版本,设备类型或应用程序版本之间找到关联。

6. Memory异常模拟

如果您有一个OutOfMemoryError,那么您可以开始创建一个内存容量低的仿真器。图2显示了AVD管理器设置,您可以在其中控制设备上的内存量。


7. 网络异常模拟

由于用户经常移入和移出 wifi/移动网络 覆盖范围,因此在应用程序网络中,异常通常不应被视为错误,而应视为意外发生的正常运行情况。

如果您需要重现网络异常(例如)UnknownHostException ,请在应用程序尝试使用网络时尝试打开飞行模式。

另一种选择是通过选择网络速度仿真或网络延迟来降低仿真器中网络的质量。您可以使用AVD管理器上的“ 速度和延迟”设置,也可以使用​​-netdelay​​​和​​-netspeed​​标志启动仿真器,如以下命令行示例所示:

emulator -avd [your-avd-image] -netdelay 20000 -netspeed gsm

此示例将所有网络请求的延迟设置为20秒,上传和下载速度为14.4 Kbps。有关仿真器的命令行选项的更多信息,请参见从命令行启动仿真器。

8. logcat 调试异常

一旦能够执行重现崩溃的步骤,便可以使用logcat之类的工具 来获取更多信息。

logcat输出将显示您还打印了哪些其他日志消息,以及系统中的其他日志消息。不要忘记关闭所有 Log 添加的语句,因为打印这些语句会在应用程序运行时浪费CPU和电池。