在“Thread.setDefaultUncaughtExceptionHandler”中显示一个对话框 [英] Show a dialog in `Thread.setDefaultUncaughtExceptionHandler`

查看:269
本文介绍了在“Thread.setDefaultUncaughtExceptionHandler”中显示一个对话框的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我的Android应用程序抛出异常时,我想显示一个自定义对话框,告诉用户发生了错误,所以我使用 Thread.setDefaultUncaughtExceptionHandler 设置一个全局异常处理程序:

  public class MyApplication extends Application {

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

Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler(){
@Override
public void uncaughtException(Thread thread,final Throwable ex){
AlertDialog.Builder builder =新的AlertDialog.Builder(getApplicationContext());
builder.setTitle(有错误)
.setMessage(应用程序将退出:+ ex.toString())
。 setPositiveButton(OK,new DialogInterface.OnClickListener(){

@Override
public void onClick(DialogInterface dialog,int which){
//再次抛出
throw(RuntimeException)ex;
}
})
.show();
}
});
}

}

但是我发现它有抛出异常, AlertDialog 不会显示,而是应用程序阻塞,一段时间后,它将显示一个系统对话框:

  X应用程序没有响应。你想关闭它吗? 
等待| OK

现在该怎么办?






更新



日志:

  11-16 12:54:16.017:WARN / WindowManager(90):尝试添加具有非应用程序令牌WindowToken {b38bb6a8 token = null}的窗口。中止。 

似乎错误来自 new AlertDialog.Builder(getApplicationContext() );



但这是应用程序子类中的异常处理程序,我如何设置一个活动实例?

解决方案

你不能从这里进行任何UI操作。只需启动另一个活动/启动屏幕。传递一个额外的意图来表示在该活动中的崩溃和显示对话框。

  / * 
*(非Javadoc)
*
* @see
* java.lang.Thread.UncaughtExceptionHandler#uncaughtException(java。
* lang.Thread,java.lang.Throwable)
* /
@Override
public void uncaughtException( Thread t,final Throwable e){
StackTraceElement [] arr = e.getStackTrace();
final StringBuffer report = new StringBuffer(e.toString());
final String lineSeperator =------------------------------- \\\
\\\
;
report.append(DOUBLE_LINE_SEP);
report.append(---------堆栈跟踪--------- \\\
\\\
); (int i = 0; i< arr.length; i ++){
report.append();

report.append(arr [i] .toString());
report.append(SINGLE_LINE_SEP);
}
report.append(lineSeperator);
//如果异常抛出在
// AsyncTask中的后台线程中,那么可以通过getCause
report.append(-------- - 原因--------- \\\
\\\
);
Throwable cause = e.getCause();
if(cause!= null){
report.append(cause.toString());
report.append(DOUBLE_LINE_SEP);
arr = cause.getStackTrace(); (int i = 0; i< arr.length; i ++){
report.append();

report.append(arr [i] .toString());
report.append(SINGLE_LINE_SEP);
}
}
//获取设备品牌,型号和sdk verion详细信息。
report.append(lineSeperator);
report.append(---------设备--------- \\\
\\\
);
report.append(品牌:);
report.append(Build.BRAND);
report.append(SINGLE_LINE_SEP);
report.append(Device:);
report.append(Build.DEVICE);
report.append(SINGLE_LINE_SEP);
report.append(Model:);
report.append(Build.MODEL);
report.append(SINGLE_LINE_SEP);
report.append(Id:);
report.append(Build.ID);
report.append(SINGLE_LINE_SEP);
report.append(Product:);
report.append(Build.PRODUCT);
report.append(SINGLE_LINE_SEP);
report.append(lineSeperator);
report.append(---------固件--------- \\\
\\\
);
report.append(SDK:);
report.append(Build.VERSION.SDK);
report.append(SINGLE_LINE_SEP);
report.append(Release);
report.append(Build.VERSION.RELEASE);
report.append(SINGLE_LINE_SEP);
report.append(Incremental:);
report.append(Build.VERSION.INCREMENTAL);
report.append(SINGLE_LINE_SEP);
report.append(lineSeperator);

Log.e(Report ::,report.toString());
Intent crashedIntent = new Intent(BaseActivity.this,SplashActivity.class);
crashedIntent.putExtra(EXTRA_CRASHED_FLAG,Unexpected Error occurred。);
crashedIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
crashedIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(crashedIntent);

System.exit(0);
//如果你没有在这里杀死虚拟机,这个应用程序进入僵局

}

另请参阅:



Android UncaughtExceptionHandler实例化AlertDialog中断



如果这是主线程崩溃,如何从UncaughtExceptionHandler启动活动?



我如何做:



我有一个BaseActivity扩展了Activity,而在onCreate的活动中我设置了UncaughtExceptionHandler。我的所有活动都扩展了BaseActivity而不是Activity。




  1. 您无法设置 Application.onCreate 中的异常处理程序,而应创建一个 BaseActivity 并将其设置在 onCreate 方法。

  2. 启动SplashActivity之后,我们应该调用 System.exit(0)

  3. 我们无法将错误实例保存到 SplashActivity 中,因为它将被销毁,相反,我们可以传递一些错误消息或将其保存在文件中。


When my android application throw an exception, I want to show a custom dialog to tell user there is something wrong happened, so I use Thread.setDefaultUncaughtExceptionHandler to set a global exception handler:

public class MyApplication extends Application {

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

        Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread thread, final Throwable ex) {
                AlertDialog.Builder builder = new AlertDialog.Builder(getApplicationContext());
                builder.setTitle("There is something wrong")
                        .setMessage("Application will exit:" + ex.toString())
                        .setPositiveButton("OK", new DialogInterface.OnClickListener() {

                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                // throw it again
                                throw (RuntimeException) ex;
                            }
                        })
                        .show();
            }
        });
    }

}

But I found it there is any exception thrown, the AlertDialog won't show, instead, the application blocks and after a while, it will show a system dialog:

X app is not responding. Would you like to close it?
Wait  |  OK

What should I do now?


UPDATE

The log:

11-16 12:54:16.017: WARN/WindowManager(90): Attempted to add window with non-application token WindowToken{b38bb6a8 token=null}.  Aborting.

It seems the error is coming from new AlertDialog.Builder(getApplicationContext());

But this is an exception handler in Application subclass, how can I set an activity instance to it?

解决方案

You cannot do any UI operation from here. Just start another activity/ splash screen. Pass an intent extra to denote crash and show dialog in that activity.

    /*
     * (non-Javadoc)
     * 
     * @see
     * java.lang.Thread.UncaughtExceptionHandler#uncaughtException(java.
     * lang.Thread, java.lang.Throwable)
     */
    @Override
    public void uncaughtException(Thread t, final Throwable e) {
        StackTraceElement[] arr = e.getStackTrace();
        final StringBuffer report = new StringBuffer(e.toString());
        final String lineSeperator = "-------------------------------\n\n";
        report.append(DOUBLE_LINE_SEP);
        report.append("--------- Stack trace ---------\n\n");
        for (int i = 0; i < arr.length; i++) {
            report.append( "    ");
            report.append(arr[i].toString());
            report.append(SINGLE_LINE_SEP);
        }
        report.append(lineSeperator);
        // If the exception was thrown in a background thread inside
        // AsyncTask, then the actual exception can be found with getCause
        report.append("--------- Cause ---------\n\n");
        Throwable cause = e.getCause();
        if (cause != null) {
            report.append(cause.toString());
            report.append(DOUBLE_LINE_SEP);
            arr = cause.getStackTrace();
            for (int i = 0; i < arr.length; i++) {
                report.append("    ");
                report.append(arr[i].toString());
                report.append(SINGLE_LINE_SEP);
            }
        }
        // Getting the Device brand,model and sdk verion details.
        report.append(lineSeperator);
        report.append("--------- Device ---------\n\n");
        report.append("Brand: ");
        report.append(Build.BRAND);
        report.append(SINGLE_LINE_SEP);
        report.append("Device: ");
        report.append(Build.DEVICE);
        report.append(SINGLE_LINE_SEP);
        report.append("Model: ");
        report.append(Build.MODEL);
        report.append(SINGLE_LINE_SEP);
        report.append("Id: ");
        report.append(Build.ID);
        report.append(SINGLE_LINE_SEP);
        report.append("Product: ");
        report.append(Build.PRODUCT);
        report.append(SINGLE_LINE_SEP);
        report.append(lineSeperator);
        report.append("--------- Firmware ---------\n\n");
        report.append("SDK: ");
        report.append(Build.VERSION.SDK);
        report.append(SINGLE_LINE_SEP);
        report.append("Release: ");
        report.append(Build.VERSION.RELEASE);
        report.append(SINGLE_LINE_SEP);
        report.append("Incremental: ");
        report.append(Build.VERSION.INCREMENTAL);
        report.append(SINGLE_LINE_SEP);
        report.append(lineSeperator);

        Log.e("Report ::", report.toString());
        Intent crashedIntent = new Intent(BaseActivity.this, SplashActivity.class);
        crashedIntent.putExtra(EXTRA_CRASHED_FLAG,  "Unexpected Error occurred.");
        crashedIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
        crashedIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        startActivity(crashedIntent);

        System.exit(0);
        // If you don't kill the VM here the app goes into limbo

    }

Also see:

Android UncaughtExceptionHandler that instantiates an AlertDialog breaks

Toast not showing up in UnCaughtExceptionHandler

How to start activity from UncaughtExceptionHandler if this is main thread crashed?

How i do it:

I have a BaseActivity which extends Activity, and in onCreate of the activity I set the UncaughtExceptionHandler. All my activities extend the BaseActivity instead of Activity.

Keys

  1. You can't set the exception handler in Application.onCreate, instead, you should create a BaseActivity and set it on the onCreate method of it.
  2. After starting the SplashActivity, we should call System.exit(0)
  3. We can't hold the error instance to share it to SplashActivity, since it will be destroyed, instead, we can pass some error message or persist it in file.

这篇关于在“Thread.setDefaultUncaughtExceptionHandler”中显示一个对话框的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆