Using Global Exception Handling on android

AndroidException Handling

Android Problem Overview


Is there a code example, or a tutorial on how to use the Thread.setDefaultUncaughtExceptionHandler method? Basically I'm trying to display a custom alert dialog, whenever an exception is thrown, in my application. Is it possible to do this? I know it's a little bit tricky to display something on the screen, if the exception is thrown in the UI thread but I don't know any work around for this.

Android Solutions


Solution 1 - Android

Basic Example for someone who comes to this page with a solution :)

public class ChildActivity extends BaseActivity {
    @SuppressWarnings("unused")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        int a=1/0;
    }
}

Class for handling error:

public class BaseActivity extends Activity{
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread paramThread, Throwable paramThrowable) {
                Log.e("Alert","Lets See if it Works !!!");
            }
        });
    }
}

Solution 2 - Android

Here's a variant of the answer by Mohit Sharma with the following improvements:

  • Doesn't cause the app/service to freeze after error handling
  • Lets Android do its normal error handling after your own

Code:

public class BaseActivity extends Activity {
	@Override
	public void onCreate() {
		super.onCreate();

		final Thread.UncaughtExceptionHandler oldHandler =
			Thread.getDefaultUncaughtExceptionHandler();
		
		Thread.setDefaultUncaughtExceptionHandler(
			new Thread.UncaughtExceptionHandler() {
				@Override
				public void uncaughtException(
					Thread paramThread,
					Throwable paramThrowable
				) {
					//Do your own error handling here
					
					if (oldHandler != null)
						oldHandler.uncaughtException(
							paramThread,
							paramThrowable
						); //Delegates to Android's error handling
					else
						System.exit(2); //Prevents the service/app from freezing
				}
			});
	}
}

Solution 3 - Android

For those who just want to see exception details when your app crashes on device (in debug config). This is application class:

private Thread.UncaughtExceptionHandler oldHandler;

@Override
public void onCreate() {
    super.onCreate();

    if (!BuildConfig.DEBUG)
        return;

    oldHandler = Thread.getDefaultUncaughtExceptionHandler();
    Thread.setDefaultUncaughtExceptionHandler((t, e) -> {
        try {
            StringWriter sw = new StringWriter();
            e.printStackTrace(new PrintWriter(sw));

            Intent intent = new Intent(Intent.ACTION_SEND);
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.putExtra(Intent.EXTRA_TEXT, sw.toString());
            intent.setType("text/plain");
            startActivity(intent);
        } catch(Exception ex) {
            ex.printStackTrace();
        } finally {
            if (oldHandler != null)
                oldHandler.uncaughtException(t, e);
            else
                System.exit(1);
        }
    });
}

It uses external app as your UI thread might not working anymore.

Solution 4 - Android

Keep in mind that the The RuntimePermission("setDefaultUncaughtExceptionHandler") is checked prior to setting the handler and make sure you cause the process to halt afterwards, by throwing an uncaught exception, as things could be in an uncertain state.

Do not display anything, indeed the UI thread might have been the one that crashed, do write a log and/or send the details to a server, instead. You might want to check out this question and its answers.

Solution 5 - Android

I just wanted to point out my experience so far. I am using the solution suggested by https://stackoverflow.com/a/26560727/2737240 to flush the exception into my log file before giving control to the default exception handler.

However, my structure looks like this:

          BaseActivity
               |
    _______________________
    |          |          |
Activity A Activity B Activity C
final Thread.UncaughtExceptionHandler defaultEH = Thread.getDefaultUncaughtExceptionHandler();                                                                                                                                                                                                                                                                                                                              
    Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {                                                                                                                                                                                                                                                                                                                                           
        @Override                                                                                                                                                                                                                                                                                                                                                                                                               
        public void uncaughtException(Thread thread, Throwable e) {                                                                                                                                                                                                                                                                                                                                                             
            handleUncaughtException(thread, e, defaultEH);                                                                                                                                                                                                                                                                                                                                                                      
        }                                                                                                                                                                                                                                                                                                                                                                                                                       
 });

where handleUncaughtException(thread, e, defaultEH); writes to the log and hands the call over to the original UncaughtExceptionHandler.

So what happened by using this code was the following:

  • Activity A is instantiated
  • New Default Exception Handler (DEH) is now my log handler + the old DEH
  • Activity B is instantiated
  • New DEH is now my log handler + the old DEH (log handler + original DEH)
  • Activity C is instantiated
  • New DEH is now my log handler + the old DEH (log handler + log handler + original DEH)

So it's a chain growing infinitely causing two problems:

  1. The specified custom code (in my case writing to the log file) will be called multiple times, which is not the desired action.
  2. The reference of defaultEh is kept in the heap even after the activity has been finished, because it is used by the reference chain so the worst thing that could happen is an out of memory exception.

Therefore I added one more thing to finally make this work without issues:

private static boolean customExceptionHandlerAttached = false;                                                                                                                                                                                                                                                                                                                                                                      
                                                                                                                                                                                                                                                                                                                                                                                                                                        
@Override                                                                                                                                                                                                                                                                                                                                                                                                                           
protected void onCreate(@Nullable Bundle savedInstanceState) {                                                                                                                                                                                                                                                                                                                                                                      
    super.onCreate(savedInstanceState);                                                                                                                                                                                                                                                                                                                                                                                             
                                                                                                                                                                                                                                                                                                                                                                                                                                        
    if(!customExceptionHandlerAttached) {                                                                                                                                                                                                                                                                                                                                                                                            
        final Thread.UncaughtExceptionHandler defaultEH = Thread.getDefaultUncaughtExceptionHandler();                                                                                                                                                                                                                                                                                                                              
        Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {                                                                                                                                                                                                                                                                                                                                           
            @Override                                                                                                                                                                                                                                                                                                                                                                                                               
            public void uncaughtException(Thread thread, Throwable e) {                                                                                                                                                                                                                                                                                                                                                             
                 handleUncaughtException(thread, e, defaultEH);                                                                                                                                                                                                                                                                                                                                                                      
            }                                                                                                                                                                                                                                                                                                                                                                                                                       
        });                                                                                                                                                                                                                                                                                                                                                                                                                         
        customExceptionHandlerAttached = true;                                                                                                                                                                                                                                                                                                                                                                                      
    }                                                                                                                                                                                                                                                                                                                                                                                                                               
}

With this solution we can make sure to:

  • add a custom exception handler for our desired action
  • ensure that this action is only triggered once
  • allowing garbage collector to dispose our activity completely by calling finish()

Solution 6 - Android

if you want use this library

https://github.com/selimtoksal/Android-Caught-Global-Exception-Library

create your TransferObject not all in your activities just use in Base activity

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionGratziView Question on Stackoverflow
Solution 1 - AndroidCode_LifeView Answer on Stackoverflow
Solution 2 - AndroidSamView Answer on Stackoverflow
Solution 3 - AndroidDrunyaView Answer on Stackoverflow
Solution 4 - AndroidluvieereView Answer on Stackoverflow
Solution 5 - AndroidGC268DMView Answer on Stackoverflow
Solution 6 - Androidsecret paladinView Answer on Stackoverflow