web-dev-qa-db-ja.com

Androidクラッシュ/強制終了時にアプリが再起動する

Androidアプリは強制終了後に再起動されます。20個のアクティビティで構成されるアプリケーション全体で、メインアクティビティで作成された静的データに依存しています。静的データは失われつつあり、アプリが実際に自動再起動すると、操作する必要のあるデータはなくなります。

私の質問は、クラッシュしたとき、私はこのことが起こるようにしたいです

  1. アプリがクラッシュした場合、アプリを再起動するのではなく、このアプリに関連するすべてのスタック/タスクをメモリから消去する必要があります。ユーザーは再び最初から再起動できます
  2. アプリの再起動を防ぐことができない場合は、少なくとも、アプリが再起動したときにそれらを元に戻すことができるように、重要なデータを保持したいです。また、再起動するときに、アプリをメインアクティビティから起動するようにします。

アクティビティがクラッシュするタイミングを知っているAndroidシステムはスタック内の次のアクティビティをフォアグラウンドに移動します。これが私のアプリが冗長な結果を生成する理由です。また、Android =開発者ですが、知っているのはマニフェストで属性を設定することだけでしたAndroid:finishOnTaskLaunch="true"。しかし、残念ながらこれは私には何の助けにもなりません。この問題を解決し、原因と分析を教えてください。

40
Techfist
  1. 静的データを使用する代わりに、Shared PreferencesまたはDatabaseにデータを保存し、もしあればuncaught Exceptionが発生し、Application has crashed and a report is sent to the adminそして、クラッシュの原因となったアクティビティを再起動します。このようにして、ユーザーはアプリケーションを引き続き使用できます。

  2. 同じことを行いますが、例外の原因となったアクティビティを再起動する代わりに、アプリケーションを再起動します。

unCaughtExceptionの処理に使用するクラスを作成します

public class MyExceptionHandler implements
        Java.lang.Thread.UncaughtExceptionHandler {
    private final Context myContext;
    private final Class<?> myActivityClass;

    public MyExceptionHandler(Context context, Class<?> c) {

        myContext = context;
        myActivityClass = c;
    }

    public void uncaughtException(Thread thread, Throwable exception) {

        StringWriter stackTrace = new StringWriter();
        exception.printStackTrace(new PrintWriter(stackTrace));
        System.err.println(stackTrace);// You can use LogCat too
        Intent intent = new Intent(myContext, myActivityClass);
        String s = stackTrace.toString();
        //you can use this String to know what caused the exception and in which Activity
        intent.putExtra("uncaughtException",
                "Exception is: " + stackTrace.toString());
        intent.putExtra("stacktrace", s);
        myContext.startActivity(intent);
        //for restarting the Activity
        Process.killProcess(Process.myPid());
        System.exit(0);
    }
}

すべてのアクティビティでこのクラスのオブジェクトを作成し、DefaultUncaughtExceptionHandlerとして設定します

    Thread.setDefaultUncaughtExceptionHandler(new MyExceptionHandler(this,
            YourCurrentActivity.class));
50
Archie.bpgc
public class MyApp extends Application {
    private static final String TAG = "MyApp";
    private static final String KEY_APP_CRASHED = "KEY_APP_CRASHED";

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

        final UncaughtExceptionHandler defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
        Thread.setDefaultUncaughtExceptionHandler( new UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread thread, Throwable exception) {
                // Save the fact we crashed out.
                getSharedPreferences( TAG , Context.MODE_PRIVATE ).edit()
                    .putBoolean( KEY_APP_CRASHED, true ).apply();
                // Chain default exception handler.
                if ( defaultHandler != null ) {
                    defaultHandler.uncaughtException( thread, exception );
                }
            }
        } );

        boolean bRestartAfterCrash = getSharedPreferences( TAG , Context.MODE_PRIVATE )
                .getBoolean( KEY_APP_CRASHED, false );
        if ( bRestartAfterCrash ) {
            // Clear crash flag.
            getSharedPreferences( TAG , Context.MODE_PRIVATE ).edit()
                .putBoolean( KEY_APP_CRASHED, false ).apply();
            // Re-launch from root activity with cleared stack.
            Intent intent = new Intent( this, MyRootActivity.class );
            intent.addFlags( Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK );
            startActivity( intent );
        }
    }
}
8
Paul
  setContentView(R.layout.current);

  Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() {

  @Override
  public void uncaughtException(Thread t, Throwable e) {
        Android.os.Process.killProcess(Android.os.Process.myPid());
        System.exit(0);
  }

  code....

(参照:Archie.bpgc)

3
PhuocLuong

静的フィールドにデータを保存しないでください。低メモリイベントでプロセスが停止し、すべてが失われる可能性があります。ユーザーがアプリに再度切り替えると、アクティビティは保存された状態から復元されますが、静的変数は復元されません。

1
konmik

ユーザーがアプリを強制的に停止している場合([設定]> [アプリ]> [アプリ情報]または最近のアプリのリストから)、またはオペレーティングシステムがアプリを停止している場合は、 onSaveInstanceState()

ただし、アプリがクラッシュする場合は、(重要なものを設定/データベース/などに定期的に保存することを除いて)それに対してできることはあまりありません。クラッシュを処理しようとするよりも、クラッシュの防止に集中する方がおそらく良いでしょう!

1
UgglyNoodle

さて、アプリケーションはインターフェース(アクティビティ)だけではありません。 SQLトランザクション、セキュリティ、Web認証などを使用する複雑なエンタープライズアプリケーションがあるとします。SharedPreferencesのみを使用して各アクティビティがアプリコンテキスト全体を回復できるようにすることはほとんど不可能です。したがって、この場合、次のコードを使用します。

public class MyApplication extends Application {
  private static final String TAG = "my.app";   
  public static final String MainActivityName = "my.app.top.activity";

  @Override
  public void onCreate() {

    try{
        ActivityManager am = (ActivityManager) this .getSystemService(ACTIVITY_SERVICE);
        List<ActivityManager.RunningTaskInfo> taskInfo = am.getRunningTasks(1);
        ComponentName componentInfo = taskInfo.get(0).topActivity;
        if (MainActivityName.length()>0 && !componentInfo.getClassName().equals(MainActivityName)){
            Log.d(TAG, "Partial Restart Not Supported! : " +componentInfo.getClassName());
            Android.os.Process.killProcess(Android.os.Process.myPid());
            System.exit(0);
            return;
        }else
            Log.d(TAG, "!!! BCSApplication topActivity=" +componentInfo.getClassName());
    }catch(Exception eee){}

    super.onCreate();
    /*
    ....
    */
 }
/*
    ....
*/
}
1
BCS Software

アプリがクラッシュしたときに、空白の画面で再開されました。これを解決するために、メインアクティビティのonCreateメソッドでsavedInstanceStateオブジェクトをチェックし、nullでない場合(Android system)によって再起動されることを意味する場合)、アクティビティを終了しました。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    if (savedInstanceState != null) {
        finish();
    }
}

あなたの場合にも役立つかもしれません。

0
Shivam