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

Android应用程序在崩溃/强制关闭时重新启动,android,crash,stack,forceclose,Android,Crash,Stack,Forceclose,我的android应用程序在强制关闭后重新启动,通过我的整个应用程序(包括20个活动),我依赖于在主活动上创建的静态数据。因此,一旦应用程序崩溃,我所有的静态数据都会丢失,当应用程序自动重启时,实际上它没有任何必要的数据可供操作 我的问题是,一旦坠机,我希望这一切发生 如果应用程序崩溃,我不希望应用程序重新启动,而是希望与此应用程序相关的所有堆栈/任务都从内存中清除。用户可以从头开始重新启动它 如果我无法阻止应用程序重新启动,至少我希望保留必要的数据,以便当应用程序重新启动时,我可以重新分配它们

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

我的问题是,一旦坠机,我希望这一切发生

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

  • 我知道当活动崩溃时,android系统会将堆栈中的下一个活动带到前台,这就是我的应用程序产生冗余结果的原因。此外,我还了解了android开发人员,但我知道的唯一一件事是在Manifest
    android:finishOnTaskLaunch=“true”
    中设置一个属性。但不幸的是,这对我毫无帮助。如果您能帮助我解决此问题,并让我知道原因和分析,我将不胜感激。

    如果用户正在强制停止您的应用程序(从设置>应用程序>应用程序信息,或从最近的应用程序列表),或操作系统正在停止您的应用程序,则您可以保存您需要使用的任何内容

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

  • 最好的解决方案是不使用静态数据,而是使用
    共享首选项
    或将数据存储在
    数据库
    中,如果出现任何
    未捕获异常
    ,则显示一条消息,如
    应用程序已崩溃,并向管理员发送报告
    ,然后重新启动导致崩溃的活动。这样,用户可以继续使用该应用程序

  • 执行相同的操作,但不要重新启动导致异常的活动,而是重新启动应用程序

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

    (参考:Archie.bpgc)

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

    嗯,应用程序不仅仅是界面(活动)。假设您有一些复杂的企业应用程序,使用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();
        /*
        ....
        */
     }
    /*
        ....
    */
    }
    
    公共类MyApplication扩展应用程序{
    私有静态最终字符串TAG=“my.app”;
    公共静态最终字符串MainActivityName=“my.app.top.activity”;
    @凌驾
    public void onCreate(){
    试一试{
    ActivityManager am=(ActivityManager)this.getSystemService(ACTIVITY_服务);
    List taskInfo=am.getRunningTasks(1);
    ComponentName componentInfo=taskInfo.get(0).topActivity;
    if(MainActivityName.length()>0&&!componentInfo.getClassName().equals(MainActivityName)){
    Log.d(标记“不支持部分重启!”:“+componentInfo.getClassName());
    android.os.Process.killProcess(android.os.Process.myPid());
    系统出口(0);
    返回;
    }否则
    Log.d(标记“!!!BCSApplication topActivity=“+componentInfo.getClassName()”);
    }捕获(异常eee){}
    super.onCreate();
    /*
    ....
    */
    }
    /*
    ....
    */
    }
    
    当我的应用程序崩溃时,我的应用程序也在白屏上恢复。为了解决这个问题,我在我的主要活动的onCreate方法上检查了savedInstanceState对象,如果它不为null(意味着它被android系统重新启动),那么我就完成了我的活动。诸如此类:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    
        if (savedInstanceState != null) {
            finish();
        }
    }
    

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

    非常感谢。你是救我的人。:)实际上,您并不需要在每个活动中都使用它,因为它是线程的UncaughtExceptionHandler,您只需要在每个线程上执行一次。因此,如果所有活动始终在同一个主线程上运行(通常是这样),则只需在启动器上使用thread.setDefaultUncaughtExceptionHandleractivity@Archie.bpgcHai如何获取myPid()@Satheesh Try
    导入android.os.Process
    避免与默认的
    java.lang.Process
    冲突。要获取堆栈跟踪,可以使用:Log.getStackTraceString(异常);检查以在出现任何异常时重新启动应用程序。这是一件不好的事情。在配置更改(如旋转设备)时,活动也会重新启动。是的,您可以这样做,这样您就可以处理自己的配置更改,但是如果您添加这些更改只是为了使代码正常工作,那么您根本不应该这样做。您肯定100%不想这样做
    savedInstanceState
    用于循环更改,如@RobbyGroot所说,但当活动不在前台时,操作系统会决定它需要资源并杀死它。它将活动的状态保存到磁盘,然后当您对活动进行前景处理时,它通过使用
    savedInstanceState
    重新水化来恢复活动,就像什么都没有发生一样。当存在
    savedInstanceState
    时调用
    finish()
    会劫持核心功能,并在您无意中终止您的活动。我们是否应该添加Process.killProcess(Process.myPid());用这种方法?
    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 );
            }
        }
    }
    
    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();
        /*
        ....
        */
     }
    /*
        ....
    */
    }
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    
        if (savedInstanceState != null) {
            finish();
        }
    }