Attend XDA's Second Annual Developer Conference, XDA:DevCon 2014!
5,733,460 Members 40,399 Now Online
XDA Developers Android and Mobile Development Forum

[GUIDE] Debugging apps

Tip us?
 
nikwen
Old
(Last edited by nikwen; 29th June 2013 at 10:53 AM.)
#1  
nikwen's Avatar
Recognized Contributor - OP
Thanks Meter 1295
Posts: 2,690
Join Date: Feb 2013
Info 2 [GUIDE] Debugging apps

Debugging apps

This is my multi-post guide on debugging apps.

Android provides its own ways of debugging:

Logcat

The most important aspect when we talk about debugging. Whenever your app crashes, you can find the reason for that in the logs (as long as you install it from your IDE).

However, we can also use it for other ways of debugging. It can help to understand how the app acts and why it does so.

Toasts

Toasts are these small pop-ups you can see in many apps. You can use them for debugging as well.

Debugger in Eclipse or Android Studio

Eclipse and Android Studio have their own debuggers. You can execute the source code step by step and see all variable values during that.

AVDs

If a user reports that the layout does not look great on his device, you can check it using an AVD, often refered to as an emulator. It can help to understand how the app will look on other devices.

Using Google and posting on XDA

Google can help you very much with your problem. If you still cannot figure out what the reasons for your problem are, you can profit by the XDA community power. However, we need some information in order to help you.


This was featured on the XDA portal on June 29, 2013.
The Following 21 Users Say Thank You to nikwen For This Useful Post: [ Click to Expand ]
 
nikwen
Old
(Last edited by nikwen; 15th June 2013 at 10:11 PM.)
#2  
nikwen's Avatar
Recognized Contributor - OP
Thanks Meter 1295
Posts: 2,690
Join Date: Feb 2013
Logcat

As I have already stated, logcats are the most important aspect of debugging on Android.

You can use them to get error messages when your app crashed or to print your own debugging information.

Understand error messages

This is one example of an error message you can get:

Code:
06-15 12:45:02.205      805-805/?                              E/AndroidRuntime: FATAL EXCEPTION: main
        java.lang.RuntimeException: Unable to start activity ComponentInfo{de.nikwen.myapplication/de.nikwen.myapplication.MainActivity}: java.lang.NullPointerException
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2180)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2230)
        at android.app.ActivityThread.access$600(ActivityThread.java:141)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1234)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:137)
        at android.app.ActivityThread.main(ActivityThread.java:5041)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:511)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
        at dalvik.system.NativeStart.main(Native Method)
        Caused by: java.lang.NullPointerException
        at de.nikwen.myapplication.MainActivity.doSomething(MainActivity.java:21)
        at de.nikwen.myapplication.MainActivity.onCreate(MainActivity.java:17)
        at android.app.Activity.performCreate(Activity.java:5104)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1080)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2144)
        ... 11 more
The code producing the error:

Code:
package de.nikwen.myapplication;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.Button;

public class MainActivity extends Activity {

    Button myButton;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        doSomething();
    }

    private void doSomething() {
        myButton.setText("Crashing here");
    }
    
}
Now we are going to analyse the error.

The second line is the most important one. It tells you which kind of error ocurred. In this case it is a NullPointerException (NPE).

Code:
java.lang.RuntimeException: Unable to start activity ComponentInfo{de.nikwen.myapplication/de.nikwen.myapplication.MainActivity}: java.lang.NullPointerException
The first thing to do now is searching for this type of error. When does it occur?

You come up with something like this:

Quote:
Thrown when an application attempts to use null in a case where an object is required. These include:
  • Calling the instance method of a null object.
(Source: http://docs.oracle.com/javase/1.4.2/...Exception.html)

Now you know what kind of Exception was thrown. You can get a lot of other useful information from the logcat:

Usually, you get some more information about the error. There should be an explanation why the Exception was thrown:

Code:
java.lang.RuntimeException: Unable to start activity ComponentInfo{de.nikwen.myapplication/de.nikwen.myapplication.MainActivity}: java.lang.NullPointerException
It also prints the stacktrace. The stacktrace contains all methods which have been invoked, the last one on the top.

In this case one exception caused another one. In most cases, the one which caused the other one is the one which is interesting for you.

Code:
Caused by: java.lang.NullPointerException
In this case the one which was thrown first is a NPE as well.

Let us have a closer look at the stacktrace:

Code:
at de.nikwen.myapplication.MainActivity.doSomething(MainActivity.java:21)
at de.nikwen.myapplication.MainActivity.onCreate(MainActivity.java:17)
at android.app.Activity.performCreate(Activity.java:5104)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1080)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2144)
The ones which are important for you usually are the ones with your package name (the red ones).
At the end of the line it tells you in which file and in which line the error occured.

Code:
at de.nikwen.myapplication.MainActivity.onCreate(MainActivity.java:17)
Here it is just the part of the code where the other method is called. So we look at the other one. (This most often happens when there are two of your methods. For that reason have a look at the upper one first.)

Code:
at de.nikwen.myapplication.MainActivity.doSomething(MainActivity.java:21)
It tells us MainActivity.java, line 21.

That is the line:

Code:
myButton.setText("Crashing here");
Remember, we got a NullPointerException. The only variable that can get null in that line is myButton. In fact we initialise it nowhere.

So this is our new onCreate method:

Code:
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
        
    myButton = (Button) findViewById(R.id.my_button);

    doSomething();
}
We solved the error.
The Following 20 Users Say Thank You to nikwen For This Useful Post: [ Click to Expand ]
 
nikwen
Old
(Last edited by nikwen; 15th June 2013 at 02:53 PM.)
#3  
nikwen's Avatar
Recognized Contributor - OP
Thanks Meter 1295
Posts: 2,690
Join Date: Feb 2013
Logcat - part II

Your own debug messages

We can also output our own debugging information that way:

Code:
Log.d("myTag", "myMessage");
or
Code:
Log.e("myTag", "myErrorMessage");
Error messages (produced with Log.e) are shown in red.

The tag can be used for filtering.

It can help us to check specific values when it does not return the right output:

Code:
Log.d("start", "hey");

String[] myStringArray = new String[] {"Hello world", "Debugging is fun (normally not ;))", "XDA is great!!!"};

String all = "Words: ";

for (String s: myStringArray) {
    Log.d("String s", s);
    all = all + s + ", ";
    Log.d("new all", all);
}
        
Log.d("status", "done");
The output:

Code:
06-15 13:15:03.014    1347-1347/de.nikwen.myapplication        D/start: hey
06-15 13:15:03.014    1347-1347/de.nikwen.myapplication        D/String s: Hello world
06-15 13:15:03.014    1347-1347/de.nikwen.myapplication        D/new all: Words: Hello world,
06-15 13:15:03.014    1347-1347/de.nikwen.myapplication        D/String s: Debugging is fun (normally not ;))
06-15 13:15:03.014    1347-1347/de.nikwen.myapplication        D/new all: Words: Hello world, Debugging is fun (normally not ;)),
06-15 13:15:03.014    1347-1347/de.nikwen.myapplication        D/String s: XDA is great!!!
06-15 13:15:03.014    1347-1347/de.nikwen.myapplication        D/new all: Words: Hello world, Debugging is fun (normally not ;)), XDA is great!!!,
06-15 13:15:03.014    1347-1347/de.nikwen.myapplication        D/status: done
You can also use the log if one of your methods does not finish:

Code:
for (int i = 0; i < 20; i--) {
    //do something
    
    Log.d("i", String.valueOf(i));
}

Log.d("status", "1");

myButton.setText("New text");

Log.d("status", "2");

Log.d("status", "done");
You can figure out the reason for logical errors by printing the required information to the logs.

If there are Exceptions you want to handle but you still want the error standard Java error message discussed in the previous post, use the printStackTrace() method of the class Exception:

Code:
try {
    Thread.sleep(5000);
} catch(Exception e) {
    e.printStackTrace();
    
    //do something here
}
The Following 9 Users Say Thank You to nikwen For This Useful Post: [ Click to Expand ]
 
nikwen
Old
(Last edited by nikwen; 15th June 2013 at 02:54 PM.)
#4  
nikwen's Avatar
Recognized Contributor - OP
Thanks Meter 1295
Posts: 2,690
Join Date: Feb 2013
Toasts

Toasts are these little windows you can see in many apps.



(Source: http://developer.android.com/images/toast.png)

You can also use them for debugging. You can output your values using Toasts instead of logcat messages.

Using Toasts for debugging is a great option, if you want to actually see the values when you test on a real device with no computer around, e.g. on the train.
It is also helpful if you want a customer to test your app. Using toasts, you can show him that something went wrong.

Do it that way:

Code:
Toast.makeText(getApplicationContext(), "My message", Toast.LENGTH_LONG).show();
(Do not forget the .show()!)

If you invoke this in an Activity, you can also do this:

Code:
Toast.makeText(this, "My message", Toast.LENGTH_LONG).show();
The disadvantage is that they are just shown for a short period of time.
The Following 7 Users Say Thank You to nikwen For This Useful Post: [ Click to Expand ]
 
nikwen
Old
(Last edited by nikwen; 27th June 2013 at 04:09 PM.)
#5  
nikwen's Avatar
Recognized Contributor - OP
Thanks Meter 1295
Posts: 2,690
Join Date: Feb 2013
Debugger in Eclipse

The debugger of Eclipse is a very productive tool. It allows you to see the values of the variables in real time. Additionally, you will be able to see and control exactly what your app is doing while it is running.

If we want to start our app in debug mode, we have to run it using the debug button.



To set or delete breakpoints we can right-click on the space left to the source code and select "Toggle Breakpoint". You will notice a blue dot next to the line. When the app is running, it will stop executing the code at the position of the breakpoint. The line with the breakpoint will not be executed.





When you run the app now, it will show a dialog which says that it is waiting for the debugger to attach.



You will also see a pop-up asking you to launch the debug perspective. Hit "Yes".





The code of your app will be executed, but it will stop before executing the line with your breakpoint. The current line which is not executed yet will be marked green.



Now you can decide what should be done next. The proper controls can be found in the debug perspective we opened before.



The one on the left will run the code until the next breakpoint will be reached. This will be the next thing we see if we define another breakpoint and press the "Resume" button:



The red button will disconnect the debugger. If you do this, your app will go on running as if no debugger had ever been attached.

Let us talk about the other buttons. The left one will make your program execute the current line and if it is a method, it will step into this method and you will be able to debug the other method step by step, too. It is called "Step into". The debugger will not be able to step into methods which are not defined by you or any library you added to your project.
If you want the debugger to execute the next line but (if the line is a method) not to step into the method, use the second button called "Step over". It will directly go to the next line.
If you are in a method and want to step out of it, use the third button. That means that it will leave the current method. Note that it will still run all code of the current method. Its name is "Step return".

In the picture above the buttons would cause this:
  • The "Step into" button will continue with the first line of the doSomething() method.
  • The "Step over" button will run the doSomething() and pause afterwards.
  • The "Step return" method will run the onCreate() method until its end and will pause then.

Now let us see how we can get the value of variables.

All variables used in the current method will be shown in the debugger view.



If there is an array, you can view its childs by clicking on the arrow next to it.



You can also view the fields of an object by clicking on the arrow.



If you hover of a variable in the code view, you will see its value, too.



I think that now you see why I call the debugger a productive tool.
And if I had shown you everything you can do with it, it would have been to long to post it on XDA. The ones I showed you are just the basic functions of the debugger.
The Following 11 Users Say Thank You to nikwen For This Useful Post: [ Click to Expand ]
 
nikwen
Old
(Last edited by nikwen; 27th June 2013 at 02:39 PM.)
#6  
nikwen's Avatar
Recognized Contributor - OP
Thanks Meter 1295
Posts: 2,690
Join Date: Feb 2013
Debugger in Android Studio

The debugger of Android Studio is a very powerful tool which allows you to see the values of the variables while your app is running on the emulator or a real device. Additionally, you will be able to see and control exactly what it is doing in real time.

In order to debug an app we need to start it using the debug button.



Then we can define or delete breakpoints by clicking on the space left to the source code. A red dot will appear there. When running the app, it will stop executing the code at the position of the breakpoint. The line with the breakpoint will not be executed.



When you run the app now, it will show a dialog which says that it is waiting for the debugger to attach.



The debug view will be opened automatically.



The code of your app will be executed, but it will stop before executing the line with your breakpoint. The current line which is not executed yet will be marked blue.



Now you can control how your app should continue. The proper controls can be found in the debug view.



The one on the left will run the code until the next brekpoint will be reached. It is called "Resume program execution". The other four buttons are for smaller steps. This will be the next thing we see if we define another breakpoint and press the "Resume program execution" button:



Let us talk about the other four buttons. The left one will make your program execute the current line and go to the next line. It is called "Step over". If you do this, it will not step into other methods and debug them.
If you want the debugger to step into the method, use the second button called "Step into". The debugger will not be able to step into methods which are not defined by you or any library you added to your project.
If you are in a method and want to step out of it, use the fourth button. That means that it will leave the current method. Note that it will still run all code of the current method. Its name is "Step out" (Surprise ).

In the picture above the buttons would cause this:
  • The "Step over" button will run the doSomething() and pause afterwards.
  • The "Step into" button will continue with the first line of the doSomething() method.
  • The "Step out" method will run the onCreate() method until its end and will pause then.

Now we talk about getting variable values.

All variables available in the current method will be shown in the debugger view.



If there is an array, you can view its childs by clicking on the plus next to it.



You can also view the fields of an object by clicking on the plus.



To see a certain value you can also hover above the variable in your code.



After that you see that the debugger is a very powerful tool.
And this is just the beginning. You can do even more complex actions with it.
The Following 8 Users Say Thank You to nikwen For This Useful Post: [ Click to Expand ]
 
nikwen
Old
(Last edited by nikwen; 15th June 2013 at 02:56 PM.)
#7  
nikwen's Avatar
Recognized Contributor - OP
Thanks Meter 1295
Posts: 2,690
Join Date: Feb 2013
AVDs

I guess that nearly every developer for Android knows them and uses them: AVDs or emulators

They are great for testing your apps on other screen sizes or platform versions.

Before releasing your app, test them on different screen sizes and (most important) on different versions of Android. Some methods are just available on new API versions and crash on old versions. Another thing to mention: If your layout is designed for large screens, it might look bad on small ones. In the same manner phone layout often look ugly on a tablet.

Creating AVDs: Official documentation
ROOTING an AVD: Guide by Androguide.fr
The Following 4 Users Say Thank You to nikwen For This Useful Post: [ Click to Expand ]
 
nikwen
Old
(Last edited by nikwen; 18th June 2013 at 08:31 PM.)
#8  
nikwen's Avatar
Recognized Contributor - OP
Thanks Meter 1295
Posts: 2,690
Join Date: Feb 2013
Using Google

Google or any other search engine is great help when you debug your app. Nearly every error which occurs for you has already been experienced by others.

If you want to find out why your app crashes, search for this:

Quote:
Android <the name of the Exception> <the method which causes the Exception>
If it is no Android specific Exception (e.g. a NumberFormatException when using Integer.parseInt("27")), replace "Android" by "Java".

If no method which is written by you is causing the crash, use keywords like these:

Quote:
Android <the name of the Exception> <the name of the superclass> <when the crash occurs>
Example for these could be:

Quote:
  • Android TextView setText CalledFromWrongThreadException
  • Android IllegalStateException Fragment orientation change
  • Java NumberFormatException Integer.parseInt
Often it is the best way to search for the message you find in the logs, e.g.

Quote:
java.lang.RuntimeException: Unable to start activity ComponentInfo{}:
android.support.v4.app.Fragment$InstantiationExcep tion: Unable to instantiate fragment:
make sure class name exists, is public, and has an empty constructor that is public
The Following 7 Users Say Thank You to nikwen For This Useful Post: [ Click to Expand ]
 
nikwen
Old
(Last edited by nikwen; 18th June 2013 at 08:43 PM.)
#9  
nikwen's Avatar
Recognized Contributor - OP
Thanks Meter 1295
Posts: 2,690
Join Date: Feb 2013
Posting on XDA

This should be your last option. Try everything you can before posting here. Though posting your problem on XDA is nothing you should be ashamed of.

However, please follow these steps to ensure that we are able to help you properly:
  1. Give us your code.
    Do not worry. You do not have to publish all of your code but the relevant parts. That means the class which causes the Exception. If you can exclude some methods to be the reason for the Exception, you do not need to post them. But do this only if you are sure that they are not important for us.
  2. Post a logcat.
    As you can see in post #2, logcats are the most important information on the bug and the reasons why it crashes.
  3. Describe the problem.
    Tell us when the code crashes. That might be that it crashes when you change the screen orientation, press the menu or back key or when a particular method is invoked. Many of us do not execute your code but just look at it in the browser. Hence we need to know when the code crashes.
The Following 12 Users Say Thank You to nikwen For This Useful Post: [ Click to Expand ]
 
matt95
Old
#10  
matt95's Avatar
Recognized Contributor
Thanks Meter 2323
Posts: 5,779
Join Date: Aug 2010
Location: Verona

 
DONATE TO ME
very very useful thanks


Donate and support my studies at the MIT University! Unruu HTC RUUs | Setup Android Development Environment on Ubuntu | Decrypt HTC RUUs

The Following 2 Users Say Thank You to matt95 For This Useful Post: [ Click to Expand ]
Tags
app, debug, debugging, exception, logcat
Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes