Android应用程序在崩溃/强制关闭时重新启动

时间:2012-09-24 07:29:31

标签: android crash stack forceclose

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

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

  1. 如果应用程序崩溃,我不希望应用程序重新启动,而是希望与此应用程序相关的所有堆栈/任务都被清除内存。用户可以从头开始重新启动它
  2. 如果我无法阻止应用重启,至少我想保留基本数据,以便在应用重启时我可以将其分配回去。此外,当它重新启动时,我希望我的应用程序从主要活动开始。
  3. 我知道当活动崩溃时,android系统会将堆栈中的下一个活动带到前台,这就是我的应用程序产生冗余结果的原因。我也经历了Android开发人员,但我唯一知道的是在Manifest android:finishOnTaskLaunch="true"中设置一个属性。但不幸的是,这对我毫无帮助。我非常感谢你帮助解决这个问题,并让我知道原因和分析。

7 个答案:

答案 0 :(得分:49)

  1. 最佳解决方案不是使用静态数据,而是使用Shared Preferences或将数据存储在Database中,如果出现任何uncaught Exception,则会显示Application has crashed and a report is sent to the admin之类的消息然后重新启动导致崩溃的Activity。这样用户可以继续使用该应用程序。

  2. 执行相同操作,但不是重新启动导致Exception的Activity,而是重新启动应用程序。

  3. 创建一个用于处理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);
        }
    }
    

    并在每个Activity中创建此类的Object并将其设置为DefaultUncaughtExceptionHandler

        Thread.setDefaultUncaughtExceptionHandler(new MyExceptionHandler(this,
                YourCurrentActivity.class));
    

答案 1 :(得分:8)

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

答案 2 :(得分:3)

  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 :(得分:1)

如果用户强行停止您的应用(来自设置&gt;应用&gt;应用信息,或来自最近的应用列表)或操作系统正在停止您的应用,那么您可以使用{{3}保存所需内容}。

但是,如果您的应用程序崩溃,那么您可以做的事情并不多(除了定期将重要内容保存到首选项/数据库/等)。最好是专注于防止崩溃,而不是试图处理崩溃!

答案 4 :(得分:1)

不要将数据存储在静态字段中。 您的进程可以在内存不足事件中停止,您将丢失所有内容。 如果用户再次切换到您的应用程序,您的活动将从已保存状态恢复,但您的静态变量将无法恢复。

答案 5 :(得分:1)

嗯,应用程序不仅仅是接口(活动)。想象一下,您有一些复杂的企业应用程序,使用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();
    /*
    ....
    */
 }
/*
    ....
*/
}

答案 6 :(得分:0)

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

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

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

这也可能对你的情况有帮助。