Android App Restarts upon Crash/force close
Asked Answered
O

7

58

My android app is getting restarted after force close, through my entire application which consist of 20 activities, I am relying on static data created on a main activity. So once the app is getting crashed all my static data is getting lost and when the app auto restarts practically it does not have any essential data to operate upon.

My question is, upon crash i want this things to happen

  1. If the app crashes, I don't want the app to restart rather I want all the stack/task related with this app to be wiped out of memory. A user can restart it from the beginning again
  2. If I can't prevent app from restart, at least I want to preserve essential data so that when the app restarts I can assign them back. Also when it restarts I want my app to start from the main activity.

I know when activity crashes android system will bring next activity in stack to foreground, and this is reason for my app producing redundant results. also i went through the android developers but only thing i got to know was setting up an attribute in Manifest android:finishOnTaskLaunch="true". But unfortunately this is of no help to me. I would appreciate your help on solving this issue, and also letting me know the cause and analysis.

Ornstead answered 24/9, 2012 at 7:29 Comment(0)
T
62
  1. Best solution would be instead of using Static data, use Shared Preferences or store data in a Database and if any uncaught Exception occurs, show a message like Application has crashed and a report is sent to the admin and then restart the Activity that caused the Crash. This way user can continue using the application.

  2. Do the same but instead of restarting the Activity which caused the Exception restart the application.

create a class used to handle 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);
    }
}

and in every Activity create an Object of this class and set it as the DefaultUncaughtExceptionHandler

    Thread.setDefaultUncaughtExceptionHandler(new MyExceptionHandler(this,
            YourCurrentActivity.class));
Threegaited answered 24/9, 2012 at 7:45 Comment(5)
actually you don't need it in every activity, as it's the Thread's UncaughtExceptionHandler, you just need to do it once on each thread. so if all your activities are always running on the same Main thread (which is usually the case), you only need to use Thread.setDefaultUncaughtExceptionHandler on your launcher activitySamoyed
@Threegaited Hai how do i get myPid()Walleyed
@Walleyed Try import android.os.Process; to avoid conflict with the default java.lang.Process.Oleviaolfaction
To get the stack trace you can use: Log.getStackTraceString(exception);Minuteman
When using this solution, if your app uses crash logging services like Firebase Crashlytics, does it still work and log the crash in addition to restarting?Gundry
B
10
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 );
        }
    }
}
Bachman answered 12/2, 2014 at 19:47 Comment(1)
shouldn't we add Process.killProcess(Process.myPid()); in this method?Yee
A
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....

(reference: Archie.bpgc)

Achromic answered 11/1, 2013 at 9:47 Comment(0)
B
3

Do not store data in static fields. Your process could be stopped on low memory event and you will lost everything. Your activities will be restored from saved state if user switch to your app again, but your static variables will not get restored.

Backslide answered 20/9, 2014 at 17:16 Comment(0)
P
3

Well, an application is not only interface(activities). Imagine you have some complex enterprise application, using SQL transactions, security, Web Authentication, etc.. It is almost impossible to make each activity able to recover the whole app context using only Shared Preferences. So in this case, I use this piece of Code:

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();
    /*
    ....
    */
 }
/*
    ....
*/
}
Psychologist answered 1/12, 2014 at 9:14 Comment(0)
I
0

If the user is force stopping your app (from Settings > Apps > App Info, or from the recent apps list) or the operating system is stopping your app, then you can save whatever you need using onSaveInstanceState().

However, if your app is crashing, then there's not much you can do about it (apart from periodically saving important stuff to preferences/databases/etc.). It is probably better to focus on preventing crashes, rather than trying to handle crashes!

Iey answered 24/9, 2012 at 7:41 Comment(0)
S
-3

My app was also getting resumed with blank screen, when it was getting crashed. To resolve this, I checked the savedInstanceState object on onCreate method of my main activity and if it is not null (means it is restarted by android system) then I finished my activity. Something like that:

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

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

It may help in your case too.

Splint answered 7/1, 2016 at 6:47 Comment(2)
This is a bad thing to do. An activity also gets restarted in configuration changes such as rotating the device. Yes, you can make it so you handle your own configuration changes, but if you add that only to make this code work properly, then you should not be doing that at all.Gargantua
You definitely, 100 percent do not want to do this. savedInstanceState is used on rotation changes, like @RobbyGroot said, but also when the Activity is not in the foreground the OS decides it needs resources and kills it. It persists the state of the Activity to disk and then when you foreground the Activity, it resumes it like nothing happen by rehydrating with savedInstanceState. To call finish() when savedInstanceState is present hijacks that core functionality and will kill your activity when you didn't intent to.Homeward

© 2022 - 2024 — McMap. All rights reserved.