在android上使用全局异常处理

时间:2010-12-13 09:44:17

标签: android exception-handling

是否有代码示例或有关如何使用Thread.setDefaultUncaughtExceptionHandler方法的教程?基本上我在我的应用程序中尝试在抛出异常时显示自定义警报对话框。是否有可能做到这一点?我知道在屏幕上显示某些内容有点棘手,如果在UI线程中抛出异常,但我不知道是否有任何解决方法。

6 个答案:

答案 0 :(得分:71)

使用解决方案来到此页面的人的基本示例:)

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

处理错误的类:

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 !!!");
            }
        });
    }
}

答案 1 :(得分:32)

以下是the answer Mohit Sharma的变体,但有以下改进:

  • 错误处理后不会导致应用/服务冻结
  • 让Android在您自己的
  • 后执行正常的错误处理

代码:

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
                }
            });
    }
}

答案 2 :(得分:4)

请记住,在设置处理程序之前检查The RuntimePermission("setDefaultUncaughtExceptionHandler"),并确保通过抛出未捕获的异常导致进程暂停,因为事情可能处于不确定状态。

不显示任何内容,实际上UI线程可能是崩溃,写日志和/或将详细信息发送到服务器的。您可能需要查看this question and its answers

答案 3 :(得分:4)

对于那些只想在应用程序在设备上崩溃时(在调试配置中)查看异常详细信息的人。这是应用程序类:

fmincon

它使用外部应用程序,因为您的UI线程可能不再起作用。

答案 4 :(得分:2)

如果您想使用该库

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

并非仅在基本活动中使用所有创建活动的TransferObject

答案 5 :(得分:2)

我只想指出到目前为止的经验。我正在使用https://stackoverflow.com/a/26560727/2737240建议的解决方案,以便在将控制权交给默认异常处理程序之前将异常刷新到我的日志文件中。

但是,我的结构如下:

          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);                                                                                                                                                                                                                                                                                                                                                                      
        }                                                                                                                                                                                                                                                                                                                                                                                                                       
 });

其中handleUncaughtException(thread, e, defaultEH);写入日志并将调用移交给原始的UncaughtExceptionHandler。

因此,使用此代码会发生以下情况:

  • 实例化活动A
  • 新的默认异常处理程序(DEH)现在是我的日志处理程序+旧的DEH
  • 活动B已实例化
  • 新的DEH现在是我的日志处理程序+旧的DEH(日志处理程序+原始DEH)
  • 实例化活动C
  • 新的DEH现在是我的日志处理程序+旧的DEH(日志处理程序+日志处理程序+原始DEH)

这是一条无限增长的链,导致两个问题:

  1. 指定的自定义代码(在我的情况下是写入日志文件)将被多次调用,这不是所需的操作。
  2. 即使活动完成后,defaultEh的引用也会保留在堆中,因为引用链使用了它,因此可能发生的最坏的情况是内存不足异常。

因此,我又添加了一件东西来最终使该工作毫无问题:

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;                                                                                                                                                                                                                                                                                                                                                                                      
    }                                                                                                                                                                                                                                                                                                                                                                                                                               
}

使用此解决方案,我们可以确保:

  • 为我们所需的操作添加自定义异常处理程序
  • 确保此操作仅触发一次
  • 允许垃圾收集器通过调用finish()完全处置我们的活动