Android: How to auto-restart an application after it has been "force closed"?
Asked Answered
H

9

90

In an Android application, we usually got the "Force Closed" error if we didn't handle the exceptions properly.

How can I restart my application automatically if it is force closed?

Is there any specific permission used for this?

Huxley answered 21/4, 2010 at 9:1 Comment(4)
Try to get the exceptions right. An application that automatically restarts itself can be annoying to users.Ious
I just want to re-start my application if it crashed. I think it would be more friendly than annoying, especially when user is in my application. And yes, I'm trying to get every exception right. :)Huxley
@Huxley : Please share solution for your problem .Distributary
check this article to restart your application on any exception.Chui
S
111

To accomplish this you have to do two things:

  1. Avoid the "Force close" - standard way of application crash.
  2. Setup a restart mechanism when the crash happens anyway.

See below how to do these:

  1. Call Thread.setDefaultUncaughtExceptionHandler() in order to catch all uncaught exception, in which case uncaughtException() method will be called. "Force close" will not appear and the application will be unresponsive, which is not a quite good thing. In order to restart your application when it crashed you should do the following :

  2. In the onCreate method, in your main activity initialize a PendingIntent member:

    Intent intent = PendingIntent.getActivity(
        YourApplication.getInstance().getBaseContext(),
        0,
        new Intent(getIntent()),
        getIntent().getFlags());
    

Then put the following in your uncaughtException() method:

AlarmManager mgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 2000, intent);
System.exit(2);

You also must call System.exit(), otherwise will not work. In this way your application will restart after 2 seconds.

Eventually you can set some flag in your intent that the application crashed and in your onCreate() method you can show a dialog "I'm sorry, the application crashed, hope never again :)".

Soong answered 25/5, 2010 at 10:44 Comment(13)
I figured that out. now the problem is where to implement uncaughtException method?? plz help. thanks.Injustice
@MayuMayooresan You can either extend the application class or Activity and do the following in onCreate(): Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler(){...});Questioning
If you extend the activity it is worth noting you need to do the same for every activity that can act as an entry point for your application (including ones that Android OS may decide to start up - for example when a window dies etc)Brightwork
It does not seem to work in ICS after forcing to stop the process via manage apps menu.Lm
@Gyuri Thanks! Problem is now I cant cancel the alarmsLi
Is it still going to report the crash to Google Play so I can analyze it?Ezechiel
YourApplication means pass the name of application or packagename or activity namePunchy
what is YourApplication means ? I used @Punchy advice, but it didn't worked. please someone explain it.Physiological
the following solution worked for me: https://mcmap.net/q/44814/-force-application-to-restart-on-first-activity (the solution stated above didn't worked because of syntax issues)Bukhara
What is YourApplication referring to here ?Abnegate
Is the class which extends android.app.Application. Check this: developer.android.com/reference/android/app/Application.htmlSoong
Applicaiton has no getInstance() method.Dorladorlisa
And an ExceptionHandler has no getSystemService method.Dorladorlisa
P
16

The trick is make sure it doesn't Force Close in the first place.

If you use the Thread.setDefaultUncaughtExceptionHandler() method you can catch the Exceptions that are causing your application to Force Close.

Have a look at this question for an example of using an UncaughtExceptionHandler to log the Exceptions raised by an application.

Pitzer answered 21/4, 2010 at 9:21 Comment(3)
Thanks for the clue. A following up question is when would the UncaughtExceptionHandler.uncaughtException be called? If user didn't click the "Force Close" button, will the UncaughtExceptionHandler.uncaughtException still be called?Huxley
@Huxley You get a Force Close when the application raises an Exception that isn't handled. If you use an UncaughtExceptionHandler then your application can handle all its Exceptions and the user will never see the Force Close dialog. In other words the UncaughtExceptionHandler is called when the Force Close dialog would have been displayed. However, you will want to be careful how you handle any unexpected Exceptions that you application catches; carrying on and pretending nothing happened is obviously risky.Pitzer
Thanks for the explanation. It explains well about the UncaughtExceptionHandler. But I've seen applications that will auto-restart after force-closed. Eg. Launcher(maybe not a good example, but I've seen third-party apps works this way as well). What if I want my app work like this? Do I have to use some kind of system permissions?Huxley
S
11

If you use Crittercism or some other error report service, accepted answer is almost right..

final UncaughtExceptionHandler defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() {
            public void uncaughtException(Thread thread, Throwable ex) {
              Intent launchIntent = new Intent(activity().getIntent());
              PendingIntent pending = PendingIntent.getActivity(CSApplication.getContext(), 0,
                    launchIntent, activity().getIntent().getFlags());
              getAlarmManager().set(AlarmManager.RTC, System.currentTimeMillis() + 2000, pending);
              defaultHandler.uncaughtException(thread, ex);
            }
});
Seow answered 2/1, 2014 at 15:14 Comment(0)
A
4

Just add this class in your package

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

In your application or in every activity class, inside the onCreate() method then simply call:

Thread.setDefaultUncaughtExceptionHandler(new MyExceptionHandler(this,
            SplashScreenActivity.class));
Augustus answered 21/11, 2017 at 17:28 Comment(0)
D
2
public class ForceCloseExceptionHandalingActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        setContentView(MyLayout());
        Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread paramThread, Throwable paramThrowable) {
                myHandaling(paramThread, paramThrowable);
            }
        });
    }

    private ViewGroup MyLayout(){
        LinearLayout mainLayout = new LinearLayout(this);
        mainLayout.setOrientation(LinearLayout.VERTICAL);  
        Button btnHello =new Button(this);
        btnHello.setText("Show all button");
        btnHello.setOnClickListener(new OnClickListener() {         
            @Override
            public void onClick(View v) {                   
                setContentView(MyLayout2());            
            }
        });             
        mainLayout.addView(btnHello);       
        return mainLayout;
    }

    private ViewGroup MyLayout2(){
        LinearLayout mainLayout = new LinearLayout(this);
        mainLayout.setOrientation(LinearLayout.VERTICAL);  
        Button btnHello =new Button(this);
        btnHello.setText("I am a EEROR uncaughtException");
        btnHello.setOnClickListener(new OnClickListener() {         
            @Override
            public void onClick(View v) {                   
                Log.e("Alert","btn  uncaughtException::");
                Toast.makeText(ForceCloseExceptionHandalingActivity.this, "Alert uncaughtException222",Toast.LENGTH_LONG).show();
                View buttone = null;
                setContentView(buttone);            
            }
        });     
        Button btnHello2 =new Button(this);
        btnHello2.setText("I am a EEROR Try n catch");
        btnHello2.setOnClickListener(new OnClickListener() {            
            @Override
            public void onClick(View v) {   

                try{
                    View buttone = null;
                    setContentView(buttone);
                }
                catch (Exception e) {
                    Log.e("Alert","Try n catch:::");
                    Toast.makeText(ForceCloseExceptionHandalingActivity.this, "Alert Try n catch",Toast.LENGTH_LONG).show();
                    setContentView(MyLayout());
                }

            }
        });     
        mainLayout.addView(btnHello);
        mainLayout.addView(btnHello2);
        return mainLayout;
    }
    public void myHandaling(Thread paramThread, Throwable paramThrowable){
        Log.e("Alert","Lets See if it Works !!!" +"paramThread:::" +paramThread +"paramThrowable:::" +paramThrowable);
        Toast.makeText(ForceCloseExceptionHandalingActivity.this, "Alert uncaughtException111",Toast.LENGTH_LONG).show();
        Intent in =new Intent(ForceCloseExceptionHandalingActivity.this,com.satya.ForceCloseExceptionHandaling.ForceCloseExceptionHandalingActivity.class);
        startActivity(in);
        finish();
        android.os.Process.killProcess(android.os.Process.myPid()); 
    }
    @Override
    protected void onDestroy() {
        Log.e("Alert","onDestroy:::");
        Toast.makeText(ForceCloseExceptionHandalingActivity.this, "Alert onDestroy",Toast.LENGTH_LONG).show();
        super.onDestroy();  
    }
Dirham answered 9/1, 2013 at 8:51 Comment(1)
this code get the "Thread.setDefaultUncaughtExceptionHandler" and call after it has been closed ..Dirham
P
1

Below is the code that worked for me. You should call appInitialization() in onCreate() method of MainActivity

    /*
    * App Restart on crash logic
    * */

    public void triggerRestart(Activity context) {
        Intent intent = new Intent(context, MainActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(intent);
        if (context instanceof Activity) {
            finish();
        }
        Runtime.getRuntime().exit(0);
    }

    private void appInitialization() {
        defaultUEH = Thread.getDefaultUncaughtExceptionHandler();
        Thread.setDefaultUncaughtExceptionHandler(_unCaughtExceptionHandler);
    }

    //make crash report on ex.stackreport
    private Thread.UncaughtExceptionHandler defaultUEH;
    // handler listener
    private Thread.UncaughtExceptionHandler _unCaughtExceptionHandler = new Thread.UncaughtExceptionHandler() {
        @Override
        public void uncaughtException(Thread thread, Throwable ex) {
            // You can code here to send crash analytics
            ex.printStackTrace();
            triggerRestart(currentActivity);
        }
    };
Pinnacle answered 2/2, 2021 at 18:46 Comment(1)
Thank you for contributing an answer. Would you kindly edit your answer to to include an explanation of your code? That will help future readers better understand what is going on, and especially those members of the community who are new to the language and struggling to understand the concepts. What are the key lines here as they relate to the OP’s question? Why are they preferred over suggestions from the existing five answers?Mccartan
A
1

For Kotlin'ers, call these two extension extension functions inside your MainActivity's onCreate() method, right after the super call and preferably before any other code you'd normally write inside onCreate().

fun Activity.handleUncaughtException() {
    Thread.setDefaultUncaughtExceptionHandler { _, throwable ->
       // here you can report the throwable exception to Sentry or Crashlytics or whatever crash reporting service you're using, otherwise you may set the throwable variable to _ if it'll remain unused
        val intent = Intent(this, MainActivity::class.java).apply {
            putExtra("isCrashed", true)
            addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
        }
        startActivity(intent)
        finish()
        Process.killProcess(Process.myPid())
        exitProcess(2)
    }
}


fun Activity.showUncaughtExceptionDialog() {
if (intent.getBooleanExtra("isCrashed", false)) {
    AlertDialog.Builder(this).apply {
        setTitle("Something went wrong.")
        setMessage("Something went wrong.\nWe'll work on fixing it.")
        setPositiveButton("OK") { _, _ -> }
    }.show()
}
}

We call Process.killProcess(Process.myPid()) and exitProcess(2) because if we look at the Android's open-source code, that's actually the default and proper handling that gets called by Thread. getDefaultUncaughtExceptionHandler(), it's what causes our applications to crash and the infamous ANR dialog brought up, and we want to be good Android citizens by following the original implementation rather than doing anything funky at the end of uncaughtException(), like not crashing at all or displaying another activity (never do this).

Note that Kotlin's exitProcess() method is just a wrapper around Java's System.exit(), whatever status code you pass in the constructor doesn't matter, I set it to 2 in my code.

Notice that in the intent we put a boolean flag "isCrashed" set to true, we'll use this to detect whether an unexpected exception caused the app to restart, and display a dialog to the user accordingly to inform them about the crash.

The showUncaughtExceptionDialog() extension function is optional, but if you're going to restart the app due to a crash, it's good manners to inform the user about it.

Attic answered 26/7, 2022 at 11:16 Comment(0)
G
0

you can use app_watchdogd.sh to watch and restart your APP with rooted Android device

Gehman answered 7/6, 2022 at 7:30 Comment(0)
F
0

you could restart app in Thread.UncaughtExceptionHandler, like below

public class MyExceptionHandler implements Thread.UncaughtExceptionHandler {

    private final Thread.UncaughtExceptionHandler defaultHandler;

    public MyExceptionHandler() {
        defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
    }

    public static void setAsDefaultUncaughtExceptionHandler() {
        Thread.setDefaultUncaughtExceptionHandler(new MyExceptionHandler());
    }

    @Override
    public void uncaughtException(@NonNull Thread thread, @NonNull Throwable throwable) {
        // save crash exception info

        SystemClock.sleep(2000);

        // restart new app process
        final Application app = YourApplication.getApplication();
        Intent launchIntentForPackage = app.getPackageManager().getLaunchIntentForPackage(app.getPackageName());
        if (launchIntentForPackage != null) {
            launchIntentForPackage.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK);
            ContextCompat.startActivity(app, launchIntentForPackage, null);
        }

        // continue crash previous app process
        if (defaultHandler != null) {
            defaultHandler.uncaughtException(thread, throwable);
        }
    }

}
Flotow answered 29/2 at 8:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.