15

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

}

しかし、例外がスローされ、AlertDialog表示されず、代わりにアプリケーションがブロックされ、しばらくするとシステム ダイアログが表示されることがわかりました。

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

私は今どうすればいい?


アップデート

ログ:

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

エラーが発生しているようですnew AlertDialog.Builder(getApplicationContext());

しかし、これはApplicationサブクラスの例外ハンドラーです。どうすればアクティビティ インスタンスを設定できますか?

4

2 に答える 2

32

ここから UI 操作を行うことはできません。別のアクティビティ/スプラッシュ画面を開始するだけです。クラッシュを示すインテント エクストラを渡し、そのアクティビティでダイアログを表示します。

    /*
     * (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

    }

以下も参照してください。

AlertDialog をインスタンス化する Android UncaughtExceptionHandler が中断する

UnCaughtExceptionHandler にトーストが表示されない

メインスレッドがクラッシュした場合、UncaughtExceptionHandler からアクティビティを開始する方法は?

私はそれを行う方法:

アクティビティを拡張する BaseActivity があり、アクティビティの onCreate で UncaughtExceptionHandler を設定しました。私のすべてのアクティビティは、Activity ではなく BaseActivity を拡張します。

キー

  1. で例外ハンドラを設定することはできませんApplication.onCreate。代わりに、 を作成してそのメソッドにBaseActivity設定する必要があります。onCreate
  2. SplashActivity を開始した後、呼び出す必要があります。System.exit(0)
  3. エラー インスタンスを保持して と共有することはできません。エラー インスタンスはSplashActivity破棄されるためです。代わりに、何らかのエラー メッセージを渡したり、ファイルに保持したりできます。
于 2012-11-16T12:57:42.563 に答える