在“Thread.setDefaultUncaughtExceptionHandler”中显示一个对话框 [英] Show a dialog in `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。
键
- 您无法设置
Application.onCreate
中的异常处理程序,而应创建一个BaseActivity
并将其设置在onCreate
方法。 - 启动SplashActivity之后,我们应该调用
System.exit(0)
- 我们无法将错误实例保存到
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
- You can't set the exception handler in
Application.onCreate
, instead, you should create aBaseActivity
and set it on theonCreate
method of it. - After starting the SplashActivity, we should call
System.exit(0)
- 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屋!