55

我的 android 应用程序在强制关闭后重新启动,通过我的整个应用程序(包括 20 个活动),我依赖于在主要活动上创建的静态数据。因此,一旦应用程序崩溃,我的所有静态数据都会丢失,并且当应用程序自动重新启动时,它实际上没有任何基本数据可供操作。

我的问题是,在崩溃时我希望这件事发生

  1. 如果应用程序崩溃,我不希望应用程序重新启动,而是希望与此应用程序相关的所有堆栈/任务都被清除内存。用户可以重新从头开始
  2. 如果我不能阻止应用重新启动,至少我想保留必要的数据,以便在应用重新启动时我可以将它们分配回来。此外,当它重新启动时,我希望我的应用程序从主要活动开始。

我知道当活动崩溃时,android 系统会将堆栈中的下一个活动带到前台,这就是我的应用程序产生冗余结果的原因。我也通过了 android 开发人员,但我只知道在 Manifest 中设置一个属性android:finishOnTaskLaunch="true"。但不幸的是,这对我没有帮助。感谢您对解决此问题的帮助,并让我知道原因和分析。

4

7 回答 7

60
  1. 最好的解决方案是不使用静态数据,而是使用Shared Preferences或存储数据,Database如果发生任何uncaught Exception情况,显示一条消息Application has crashed and a report is sent to the admin,然后重新启动导致崩溃的 Activity。这样用户可以继续使用该应用程序。

  2. 做同样的事情,但不要重新启动导致异常重新启动应用程序的 Activity。

创建一个用于处理的类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));
于 2012-09-24T07:45:22.830 回答
9
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 );
        }
    }
}
于 2014-02-12T19:47:12.717 回答
4
  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)

于 2013-01-11T09:47:05.697 回答
3

不要将数据存储在静态字段中。您的进程可能会因内存不足事件而停止,您将失去一切。如果用户再次切换到您的应用程序,您的活动将从保存状态恢复,但您的静态变量不会恢复。

于 2014-09-20T17:16:26.420 回答
3

好吧,应用程序不仅仅是界面(活动)。想象一下,您有一些复杂的企业应用程序,使用 SQL 事务、安全性、Web 身份验证等。仅使用共享首选项使每个活动都能够恢复整个应用程序上下文几乎是不可能的。所以在这种情况下,我使用这段代码:

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();
    /*
    ....
    */
 }
/*
    ....
*/
}
于 2014-12-01T09:14:07.557 回答
0

如果用户强制停止您的应用程序(从设置 > 应用程序 > 应用程序信息,或从最近的应用程序列表)或操作系统正在停止您的应用程序,那么您可以使用onSaveInstanceState().

但是,如果您的应用程序崩溃,那么您无能为力(除了定期将重要内容保存到首选项/数据库/等)。最好专注于防止崩溃,而不是尝试处理崩溃!

于 2012-09-24T07:41:05.833 回答
-2

当它崩溃时,我的应用程序也以空白屏幕恢复。为了解决这个问题,我检查了我主要活动的 onCreate 方法上的 savedInstanceState 对象,如果它不为空(意味着它被 android 系统重新启动),那么我完成了我的活动。像这样的东西:

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

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

它也可能对您的情况有所帮助。

于 2016-01-07T06:47:33.750 回答