Logging unhandled exceptions in Android Activity

偶尔善良 提交于 2019-12-12 16:46:55

问题


I have created a class BaseActivity extends AppCompatActivity from which all my Activites in an Android App are inheriting.

In this class I intended to catch all unhandled exceptions, so I can write them to a local SQLite database for later inspection / sending to remote server.

Below I attach entire class code:

public class BaseActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    final Thread.UncaughtExceptionHandler defaultHandler = Thread.getDefaultUncaughtExceptionHandler();

    Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
        @Override
        public void uncaughtException(Thread paramThread, Throwable paramThrowable) {
            Log.e("Uncaught Exception", paramThrowable.getMessage());
            logError(paramThrowable);
            defaultHandler.uncaughtException(paramThread, paramThrowable);
        }
    });
}

private void logError(final Throwable paramThrowable){
    try {
        ApplicationError error = new ApplicationError();

        String stackTrace = "";
        for (int i = 0; i < paramThrowable.getStackTrace().length; i++) {
            stackTrace += paramThrowable.getStackTrace()[i].toString() + "\n";
        }

        Throwable tmp = paramThrowable;
        int j = 0;
        while ((tmp = tmp.getCause()) != null && j < 5) {
            j++;
            stackTrace += "Coused by:\n";
            for (int i = 0; i < tmp.getStackTrace().length; i++) {
                stackTrace += tmp.getStackTrace()[i].toString() + "\n";
            }
        }

        Log.e("Saving error...", "");

        String deviceInfo = "";
        deviceInfo += "OS version: " + System.getProperty("os.version") + "\n";
        deviceInfo += "API level: " + Build.VERSION.SDK_INT + "\n";
        deviceInfo += "Manufacturer: " + Build.MANUFACTURER + "\n";
        deviceInfo += "Device: " + Build.DEVICE + "\n";
        deviceInfo += "Model: " + Build.MODEL + "\n";
        deviceInfo += "Product: " + Build.PRODUCT + "\n";

        error.mDeviceInfo = deviceInfo;
        error.mErrorMessage = paramThrowable.getMessage();
        error.mStackTrace = stackTrace;

        error.save();

        Log.e("Saved error:", error.mErrorMessage + "\n" + error.mStackTrace);
    }catch(Exception e){

    }
}

}

For clarification: ApplicationError is just a model class which handles saving to the database using DBFlow.

The problem

Each time an unhandled exception occurs (doesn't matter what it is) in an activity two weird things happen:

  1. The logError() method is called more than once, sometimes even 8-10 times. Looking at logs I can see they have almost the same timestamp.
  2. A message 'XXX Application has stopped" is shown on a device screen (which is fine), but after closing it the application is hanged and I need to force-stop from application settings screen.

Can anyone help me with this? Or is there a better approach to the problem?


回答1:


I managed to finally solve this with help of AAG's answer.

@AAG you were right, the exception handler was being added each time an onCreate() method in any activity was called.

@AAG But you were wrong about not using defaultHandler. I have to use it, for Android to properly handle application crash.

Thanks for your help!

This is the fixed code:

public class BaseActivity extends AppCompatActivity {

    public static Context applicationContext = null;
    public static Thread.UncaughtExceptionHandler defaultHandler = null;
    public static Thread.UncaughtExceptionHandler exceptionHandler = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if(defaultHandler == null){
            defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
        }

        if(applicationContext == null){
            applicationContext = getApplicationContext();
        }

        if(exceptionHandler == null){
            exceptionHandler = new Thread.UncaughtExceptionHandler() {
                @Override
                public void uncaughtException(Thread paramThread, Throwable paramThrowable) {
                    Log.e("Uncaught Exception", paramThrowable.getMessage());
                    logError(paramThrowable);
                    defaultHandler.uncaughtException(paramThread, paramThrowable);

                }
            };

            Thread.setDefaultUncaughtExceptionHandler(exceptionHandler);
        }
    }

    private static void logError(final Throwable paramThrowable){
        try {
            ApplicationError error = new ApplicationError();

            String stackTrace = "";
            for (int i = 0; i < paramThrowable.getStackTrace().length; i++) {
                stackTrace += paramThrowable.getStackTrace()[i].toString() + "\n";
            }

            Log.e("Saving error...", "");

            Throwable tmp = paramThrowable;
            int j = 0;
            while ((tmp = tmp.getCause()) != null && j < 5) {
                j++;
                stackTrace += "Coused by:\n";
                for (int i = 0; i < tmp.getStackTrace().length; i++) {
                    stackTrace += tmp.getStackTrace()[i].toString() + "\n";
                }
            }

            String deviceInfo = "";
            deviceInfo += "OS version: " + System.getProperty("os.version") + "\n";
            deviceInfo += "API level: " + Build.VERSION.SDK_INT + "\n";
            deviceInfo += "Manufacturer: " + Build.MANUFACTURER + "\n";
            deviceInfo += "Device: " + Build.DEVICE + "\n";
            deviceInfo += "Model: " + Build.MODEL + "\n";
            deviceInfo += "Product: " + Build.PRODUCT + "\n";

            error.mDeviceInfo = deviceInfo;
            error.mErrorMessage = paramThrowable.getMessage();
            error.mStackTrace = stackTrace;

            error.save();

            Log.e("Saved error:", error.mErrorMessage + "\n" + error.mStackTrace);
        }catch(Exception e){

        }
    }

}



回答2:


in your handler, you are calling

defaultHandler.uncaughtException(paramThread, paramThrowable);

you should not be doing this. Everytime onCreate is called (which can be many depending on how your app is used) - you are creating a handler that calls the old handler. so the third time onCreate is call, you will call the handler that was created on the second call, and then the handler that was created on the first call.

after removing this, your onCreate method should now be:

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);


    Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
        @Override
        public void uncaughtException(Thread paramThread, Throwable paramThrowable) {
            Log.e("Uncaught Exception", paramThrowable.getMessage());
            logError(paramThrowable);
        }
    });

}



来源:https://stackoverflow.com/questions/35876515/logging-unhandled-exceptions-in-android-activity

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!