The Art Students Need to Work on Making a Stop Sign for the Show Using Stacks of Figures
An Android app crashes whenever there'due south an unexpected get out acquired by an unhandled exception or point. An app that is written using Java or Kotlin crashes if it throws an unhandled exception, represented past the Throwable
course. An app that is written using native-lawmaking languages crashes if there'southward an unhandled bespeak, such every bit SIGSEGV, during its execution.
When an app crashes, Android terminates the app's process and displays a dialog to allow the user know that the app has stopped, as shown in figure 1.
An app doesn't demand to exist running in the foreground for information technology to crash. Whatever app component, even components like broadcast receivers or content providers that are running in the groundwork, can cause an app to crash. These crashes are often disruptive for users because they were not actively engaging with your app.
If your app is experiencing crashes, yous can employ the guidance in this page to diagnose and fix the problem.
Detect the problem
You lot may non always know that your users are experiencing an inordinate number of crashes with your app. If y'all have already published your app, Android vitals can help brand you aware of the problem.
Android vitals
Android vitals can help improve your app's performance past alerting you, via the Play Panel, when your app is exhibiting excessive crashes. Android vitals considers crashes excessive when an app:
- Exhibits at least i crash in at least ane.09% of its daily sessions.
- Exhibits 2 or more crashes in at least 0.18% of its daily sessions.
A daily session refers to a 24-hour interval in which your app was used. For information on how Google Play collects Android vitals data, see the Play Console documentation.
After y'all learn that your app is suffering from besides many crashes, the next step is to diagnose them.
Diagnose the crashes
Solving crashes can be difficult. Yet, if you can identify the root crusade of the crash, about probable y'all can find a solution to information technology.
There are many situations that can cause a crash in your app. Some reasons are obvious, similar checking for a nothing value or empty string, merely others are more subtle, like passing invalid arguments to an API or even complex multithreaded interactions.
Crashes on Android produce a stack trace, which is a snapshot of the sequence of nested functions called in your program up to the moment it crashed. Yous can view crash stack traces in Android vitals.
Reading a stack trace
The start step to fix a crash is to identify the identify where it happens. Y'all can use the stack trace bachelor in the report details if you are using Play Console or the output of the logcat tool. If y'all don't have a stack trace available, y'all should locally reproduce the crash, either by manually testing the app or by reaching out to affected users, and reproduce it while using logcat.
The post-obit trace shows an example of a crash on an app written using the Java programming language:
--------- showtime of crash AndroidRuntime: FATAL EXCEPTION: main Process: com.android.developer.crashsample, PID: 3686 java.lang.NullPointerException: crash sample at com.android.developer.crashsample.MainActivity$ane.onClick(MainActivity.java:27) at android.view.View.performClick(View.java:6134) at android.view.View$PerformClick.run(View.coffee:23965) at android.os.Handler.handleCallback(Handler.java:751) at android.os.Handler.dispatchMessage(Handler.java:95) at android.bone.Looper.loop(Looper.java:156) at android.app.ActivityThread.principal(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 organization
A stack trace shows two pieces of information that are critical to debugging a crash:
- The type of exception thrown.
- The department of lawmaking where the exception is thrown.
The type of exception thrown is usually a very stiff hint as to what went wrong. Look at whether information technology is an IOException
, an OutOfMemoryError
, or something else, and detect the documentation almost the exception class.
The class, method, file, and line number of the source file where the exception is thrown is shown on the 2nd line of a stack trace. For each role that was chosen, another line shows the preceding call site (called a stack frame). By walking upward the stack and examining the lawmaking, you may discover a identify that is passing an incorrect value. If your code doesn't appear in the stack trace, information technology is likely that somewhere, you passed an invalid parameter into an asynchronous operation. You can oftentimes figure out what happened by examining each line of the stack trace, finding any API classes that you lot used, and confirming that the parameters you passed were correct, and that y'all called it from a place that is allowed.
Stack traces for apps with C and C++ code work much the same way.
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** Build fingerprint: 'google/foo/bar:10/123.456/78910:user/release-keys' ABI: 'arm64' Timestamp: 2020-02-16 xi:16:31+0100 pid: 8288, tid: 8288, name: com.example.testapp >>> com.example.testapp <<< uid: 1010332 signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), error addr 0x0 Cause: null pointer dereference x0 0000007da81396c0 x1 0000007fc91522d4 x2 0000000000000001 x3 000000000000206e x4 0000007da8087000 x5 0000007fc9152310 x6 0000007d209c6c68 x7 0000007da8087000 x8 0000000000000000 x9 0000007cba01b660 x10 0000000000430000 x11 0000007d80000000 x12 0000000000000060 x13 0000000023fafc10 x14 0000000000000006 x15 ffffffffffffffff x16 0000007cba01b618 x17 0000007da44c88c0 x18 0000007da943c000 x19 0000007da8087000 x20 0000000000000000 x21 0000007da8087000 x22 0000007fc9152540 x23 0000007d17982d6b x24 0000000000000004 x25 0000007da823c020 x26 0000007da80870b0 x27 0000000000000001 x28 0000007fc91522d0 x29 0000007fc91522a0 sp 0000007fc9152290 lr 0000007d22d4e354 pc 0000007cba01b640 backtrace: #00 pc 0000000000042f89 /information/app/com.instance.testapp/lib/arm64/libexample.so (com::example::Crasher::crash() const) #01 pc 0000000000000640 /data/app/com.case.testapp/lib/arm64/libexample.so (com::case::runCrashThread()) #02 pc 0000000000065a3b /system/lib/libc.so (__pthread_start(void*)) #03 pc 000000000001e4fd /system/lib/libc.so (__start_thread)
If you don't see class and role-level data in native stack traces, you may need to generate a native debug symbols file and upload it to the Google Play Console. For more information, see Deobfuscate crash stack traces. For general information on native crashes, run into Diagnosing native crashes.
Tips for reproducing a crash
It's possible that you can't quite reproduce the problem just by starting an emulator or connecting your device to your computer. Development environments tend to accept more resources, such as bandwidth, retentivity, and storage. Use the type of exception to determine what could be the resource that is deficient, or find a correlation betwixt the version of Android, device type or your app's version.
Retentivity errors
If you take an OutOfMemoryError
, so you could create an emulator with low memory capacity to test with. Figure 2 shows the AVD manager settings where y'all tin command the amount of retention on the device.
Networking exceptions
Since users oft move in and out of mobile or WiFi network coverage, in an application network exceptions unremarkably should not be treated every bit errors, but rather as normal operating weather condition that happen unexpectedly.
If you need to reproduce a network exception, such as an UnknownHostException
, then try turning on airplane fashion while your application attempts to use the network.
Another option is to reduce the quality of the network in the emulator by choosing a network speed emulation and/or a network delay. Y'all can use the Speed and Latency settings on AVD manager, or you can start the emulator with the -netdelay
and -netspeed
flags, as shown in the following command-line example:
emulator -avd [your-avd-paradigm] -netdelay 20000 -netspeed gsm
This example sets a delay of 20 seconds on all network requests and an upload and download speed of xiv.4 Kbps. For more than information on command-line options for the emulator, see Start the emulator from the command line.
Reading with logcat
Once y'all are able have the steps to reproduce the crash, y'all can use a tool like logcat to get more information.
The logcat output will show you what other log messages yous take printed, along with others from the arrangement. Don't forget to turn off whatsoever extra Log
statements that you take added considering printing them wastes CPU and bombardment while your app is running.
Prevent crashes caused by null arrow exceptions
Nil pointer exceptions (identified past the runtime error blazon NullPointerException
) occur when you're trying to access an object that is zilch, typically past invoking its methods or accessing its members. Null pointer exceptions are the largest crusade of app crashes on Google Play. The purpose of cipher is to signify that the object is missing - for case, information technology hasn't been created or assigned even so. To avoid null arrow exceptions, you demand to make sure that the object references yous're working with are non-nix before calling methods on them or trying to access their members. If the object reference is null, handle this instance well (for example, exit from a method earlier performing whatever operations on the object reference and write information to a debug log).
Because you don't want to take null checks for every parameter of every method called, you tin rely on the IDE or on the type of the object to signify nullability.
Java programming language
The following sections apply to the Java programming language.
Compile fourth dimension warnings
Comment your methods' parameters and return values with @Nullable
and @NonNull
to receive compile time warnings from the IDE. These warnings prompt yous to expect a nullable object:
These nothing checks are for objects that you lot know could be cipher. An exception on a @NonNull
object is an indication of an error in your code that needs to be addressed.
Compile time errors
Because nullability should be meaningful, you can embed it in the types you utilise then that there is a compile fourth dimension check for nada. If yous know an object tin can be zippo and that nullability should be handled, you lot could wrap it in an object like Optional
. You should e'er prefer types that convey nullability.
Kotlin
In Kotlin, nullability is role of the type system. For example, a variable needs to exist declared from the beginning as nullable or not-nullable. Nullable types are marked with a ?
:
// non-null var s: String = "Howdy" // null var s: Cord? = "Hello"
Non-nullable variables cannot be assigned a goose egg value and nullable variables demand to be checked for nullability before being used as non-aught.
If you don't desire to check for null explicitly, you can utilize the ?.
safe call operator:
val length: Int? = string?.length // length is a nullable int // if cord is null, and so length is zip
Every bit a all-time practise, make sure you accost the null example for a nullable object, or your app could get into unexpected states. If your application won't crash anymore with NullPointerException
, you won't know that these errors exist.
The post-obit are some ways to bank check for cipher:
-
if
checksval length = if(string != null) string.length else 0
Due to smart-cast and the null check, the Kotlin compiler knows that the cord value is non-null so it allows you to utilize the reference directly, without the need for the safe call operator.
-
?:
Elvis operatorThis operator allows yous to land "if the object is non-null, return the object; otherwise, return something else".
val length = string?.length ?: 0
You can withal go a NullPointerException
in Kotlin. The following are the nigh common situations:
- When you're explicitly throwing a
NullPointerException
. - When you're using the null assertion
!!
operator. This operator converts any value to a non-zippo type, throwingNullPointerException
if the value is nada. - When accessing a cypher reference of a platform type.
Platform types
Platform types are object declarations coming from Java. These types are particularly-treated; goose egg checks are not as enforced, so the non-cypher guarantee is the same every bit in Java. When y'all access a platform type reference, Kotlin does not create compile time errors only these references tin can lead to runtime errors. Run into the following example from the Kotlin documentation:
val list = ArrayList<Cord>() // non-null (constructor result) listing.add together("Item") val size = list.size // non-null (primitive int) val particular = list[0] // platform type inferred (ordinary Java object) item.substring(1) // allowed, may throw an // exception if item == null
Kotlin relies on blazon inference when a platform value is assigned to a Kotlin variable, or y'all tin can define what type to expect. The best way to ensure the correct nullability country of a reference coming from Java is to use nullability annotations (for case, @Nullable
) in your Java code. The Kotlin compiler will represent these references as actual nullable or non-nullable types, not as platform types.
Java Jetpack APIs have been annotated with @Nullable
or @NonNull
as needed, and a similar approach has been taken in the Android 11 SDK. Types coming from this SDK, that are used in Kotlin, will exist represented as correct nullable or non-nullable types.
Considering of Kotlin's type system, nosotros've seen apps take a major reduction in NullPointerException
crashes. For example, the Google Home app saw a 30% reduction in crashes caused by naught arrow exceptions during the year that it migrated new feature evolution to Kotlin.
Source: https://developer.android.com/topic/performance/vitals/crash