78

For an unknown reason, I can't get my application leaving properly so that when I push the home button and the app icon again, I resume where I was in the app. I would like to force the application to restart on the first Activity.

I suppose this has something to do with onDestroy() or maybe onPause() but I don't know what to do.

tshepang
  • 12,111
  • 21
  • 91
  • 136
Sephy
  • 50,022
  • 30
  • 123
  • 131

12 Answers12

158

Here is an example to restart your app in a generic way by using the PackageManager:

Intent i = getBaseContext().getPackageManager()
             .getLaunchIntentForPackage( getBaseContext().getPackageName() );
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(i);
Damia Fuentes
  • 5,308
  • 6
  • 33
  • 65
Marc
  • 1,620
  • 1
  • 11
  • 3
  • 3
    It help me.Thanks. I used like that,"try { Intent i; i = getBaseContext().getPackageManager() .getLaunchIntentForPackage( getBaseContext().getPackageName() ); i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(i); } catch (NameNotFoundException e) { e.printStackTrace(); } – tknv Jan 19 '11 at 06:06
  • One problem with this approach. new activity's onCreate is called before old activity stack gets onDestroy – AAverin Mar 13 '14 at 11:35
  • 1
    @AAverin: how can I get onDestroy to be called before onCreate? – oligofren Mar 14 '14 at 13:02
  • Probably related with above issue: this does not seem to be working from child activities. I have used it in a PreferenceActivity called with FLAG_ACTIVITY_NO_HISTORY, and I am not getting the expected behavior from a full restart (I believe some of my instanced booleans are not being cleared exactly because onCreate comes up before onDestroy on the _Launcher_ activity). – leRobot Jun 05 '14 at 19:22
  • this works great for me, except when I then navigate to another activity, press the home button, then launch my app again through the icon, I'm now brought to a new instance of my main activity on top of my back stack, since mine is set to a launchMode of "singleTop" See my answer below for how I added in a fix for this – Mike Venzke Jul 10 '14 at 22:55
  • 8
    not working, just resume in launch activity , the application class not reset –  Dec 01 '14 at 06:35
  • Are static variables/properties reinitialized here as well? – TomeeNS Dec 09 '15 at 02:34
  • But if i call this method from my tests(espresso) for example, how i can correct to restart my app? – Morozov Feb 21 '17 at 12:20
  • Thanks for the solution i was looking so long..works fine – Rafiq Ahmad Dec 12 '17 at 05:31
  • 2
    Use flags as `Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK`, this works great and clears the activity stack as well. – Lalit Fauzdar Mar 08 '18 at 07:40
31

The solution marked as 'answer' works but has one disadvantage that was critical for me. With FLAG_ACTIVITY_CLEAR_TOP your target activity will get onCreate called before your old activity stack receives onDestroy. While I have been clearing some necessary stuff in onDestroy I had to workaroud.

This is the solution that worked for me:

public static void restart(Context context, int delay) {
    if (delay == 0) {
        delay = 1;
    }
    Log.e("", "restarting app");
    Intent restartIntent = context.getPackageManager()
            .getLaunchIntentForPackage(context.getPackageName() );
    PendingIntent intent = PendingIntent.getActivity(
            context, 0,
            restartIntent, Intent.FLAG_ACTIVITY_CLEAR_TOP);
    AlarmManager manager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    manager.set(AlarmManager.RTC, System.currentTimeMillis() + delay, intent);
    System.exit(2);
}

The idea is to fire a PendingIntent via AlarmManager that will be invoked a bit later, giving old activity stack some time to clear up.

AAverin
  • 3,014
  • 3
  • 27
  • 32
  • 1
    Why don't you just call the `Activity`'s `finish()` method instead of `System.exit`? The doc says "Call this when your activity is done and should be closed." – oligofren Mar 14 '14 at 13:22
  • 1
    I just realized that it's due to the method being static, thus not being able to call any non-static methods such as `finish`. I just made `restart` non-static, and replaced the System.exit call instead. – oligofren Mar 14 '14 at 13:27
  • 1
    And after testing, I found out that using finish() causes my app to hang on startup, while System.exit works fine ... – oligofren Mar 14 '14 at 14:25
  • 3
    agree with previous comment. I've used PendingIntent.FLAG_CANCEL_CURRENT instead of Intent.FLAG_ACTIVITY_CLEAR_TOP to remove warning – Alexeev Valeriy Nov 21 '15 at 20:06
15

if you want to always start at the root you want to set android:clearTaskOnLaunch to true on your root activity

jqpubliq
  • 11,874
  • 2
  • 34
  • 26
  • 1
    yeah I tried that but then when i click the icon again it seems to call on Resume instead of onCreate... which means I get a screen without any of my methods starting – Sephy Mar 18 '10 at 17:07
  • 2
    Or add the flag `Intent.FLAG_ACTIVITY_CLEAR_TASK` programmatically to the Intent. – Davideas May 17 '15 at 14:04
9
android:clearTaskOnLaunch="true"
android:launchMode="singleTask"

Use this property in manifest file in starting class (first activity).

user1438038
  • 5,821
  • 6
  • 60
  • 94
Rishi Gautam
  • 1,948
  • 3
  • 21
  • 31
3

Does FLAG_ACTIVITY_CLEAR_TOP do what you need to do?

Intent i = new Intent(getBaseContext(), YourActivity.class);
            i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
            startActivity(i);
Bert
  • 101
  • 1
  • 3
3

FLAG_ACTIVITY_CLEAR_TOP didn't work for me because I had to support 2.3.3. My first solution was:

Intent intent = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());
    intent.addFlags(Build.VERSION.SDK_INT >= 11 ? Intent.FLAG_ACTIVITY_CLEAR_TASK : Intent.FLAG_ACTIVITY_CLEAR_TOP);
context.startActivity(intent);

This almost works, but not quite.

Since I have a base Activity, I added a kill broadcast that closes all my running activities.

public abstract class BaseActivity extends AppCompatActivity {

    private static final String ACTION_KILL = "BaseActivity.action.kill";
    private static final IntentFilter FILTER_KILL;
    static {
        FILTER_KILL = new IntentFilter();
        FILTER_KILL.addAction(ACTION_KILL);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        registerReceiver(killReceiver, FILTER_KILL);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(killReceiver);
    }

    private final BroadcastReceiver killReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            finish();
        }
    };

    public void killApp(){
        sendBroadcast(new Intent(ACTION_KILL));
    }
}

All of my activities extend from this class, so

((BaseActivity)getActivity()).killApp();
startActivity(new Intent(getActivity(), StartActivity.class));

restarts the app. Tested on genymotion v10, v16, v21 and Nexus 5 with v22.

Edit: this does not remove an activity if it is destroyed at the time of sending the intent. I'm still looking for a solution.

DariusL
  • 4,007
  • 5
  • 32
  • 44
3

The following code is work for me, it can restart full app perfectly!

Intent mStartActivity = new Intent(context, StartActivity.class);
int mPendingIntentId = 123456;
PendingIntent mPendingIntent = PendingIntent.getActivity(context,mPendingIntentId,    mStartActivity, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager mgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, mPendingIntent);
System.exit(0);
Beatrice Lin
  • 1,456
  • 14
  • 17
  • What is the meaning of the value of `mPendingIntentId`? Looks like a particularly magical number - is it just an arbitrary int? – aaaidan Nov 22 '17 at 21:38
  • It's just an arbitrary number, you can use any random integer. It's a message number in PendingIntent class. – Beatrice Lin Nov 28 '17 at 04:02
2

Marc's answer works great, except in my case where my main activity has a launchMode of singleTop. Once I run this intent and then navigate to new Activities and press the home button on the device, then launch my app again from the app icon, I end up creating a new instance of the main Activity, with my previous activity on the back stack.

According to this question it's because the intents don't match. Looking at adb dumpsys activity, I see that from my standard android launcher, the package is null, whereas when I do as Marc suggests, the intent package is the name of my package. This difference causes them to not match and to start a new instance when the app icon is tapped again and the main activity isn't on top.

However, on other launchers, like on Kindle, the package is set on the launcher intent, so I needed a generic way to handle launchers. I added static methods like such:

static boolean mIsLaunchIntentPackageNull = true;    

public static boolean isLaunchIntent(Intent i) {
    if (Intent.ACTION_MAIN.equals(i.getAction()) && i.getCategories() != null
            && i.getCategories().contains(Intent.CATEGORY_LAUNCHER)) {
        return true;
    }

    return false;
}

public static void handleLaunchIntent(Intent i) {
    if (isLaunchIntent(i)) {
        if (i.getPackage() != null) {
            mIsLaunchIntentPackageNull = false;
        }
        else {
            mIsLaunchIntentPackageNull = true;
        }
    }
}

with a go home mechanism like this:

    Intent intentHome = appContext.getPackageManager()
            .getLaunchIntentForPackage( appContext.getPackageName());
    intentHome.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

    // need to match launcher intent exactly to avoid duplicate activities in stack
    if (mIsLaunchIntentPackageNull) {
        intentHome.setPackage(null);
    }
    appContext.startActivity(intentHome);

then in the main activity defined in my manifest, I added this line:

public void onCreate(Bundle savedInstanceState) {
    [class from above].handleLaunchIntent(getIntent());

this works for me on kindle and my phone, and lets me properly reset the app w/o adding another instance of the main activity.

Community
  • 1
  • 1
Mike Venzke
  • 754
  • 6
  • 10
2

You can use Jake Wharton's lib ProcessPhoenix in order to restart your application process.

mol
  • 2,607
  • 4
  • 21
  • 40
1

this worked for me:

Intent mStartActivity = new Intent(ctx.getApplicationContext(), ActivityMain.class);


    mStartActivity.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    mStartActivity.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
        mStartActivity.addFlags(0x8000); // equal to Intent.FLAG_ACTIVITY_CLEAR_TASK

   int mPendingIntentId = 123456;


    PendingIntent mPendingIntent = PendingIntent.getActivity(ctx, mPendingIntentId, mStartActivity, PendingIntent.FLAG_CANCEL_CURRENT);
    AlarmManager mgr = (AlarmManager) ctx.getSystemService(Context.ALARM_SERVICE);
    mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 1000, mPendingIntent);

    ActivityManager manager =  (ActivityManager) ctx.getApplicationContext().getSystemService(ctx.getApplicationContext().ACTIVITY_SERVICE);
    List<ActivityManager.RunningAppProcessInfo> activityes = ((ActivityManager)manager).getRunningAppProcesses();




    ((Activity)ctx).moveTaskToBack(true);
    manager.killBackgroundProcesses("com.yourpackagename");
    System.exit(0);
0

You should checkout this question:

Restarting Android app programmatically

The way to do it is:

private void restartApp() 
{
   Intent intent = new Intent(getApplicationContext(), YourStarterActivity.class);
   int mPendingIntentId = MAGICAL_NUMBER;
   PendingIntent mPendingIntent = PendingIntent.getActivity(getApplicationContext(), mPendingIntentId, intent, PendingIntent.FLAG_CANCEL_CURRENT);
   AlarmManager mgr = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
   mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, mPendingIntent);
   System.exit(0);
}
CodeMonkey
  • 11,196
  • 30
  • 112
  • 203
-1

After hard thinking and testing I finally got the right way of calling my activity to recreate when the app is left with the home button :

android:clearTaskOnLaunch

in the manifest

@Override
public void onRestart(){
    onCreate();
}

That does the trick...(better than when it is put in onResume which is called each time you launch the app, even the first time, causing a double display)

Eonasdan
  • 7,563
  • 8
  • 55
  • 82
Sephy
  • 50,022
  • 30
  • 123
  • 131
  • 2
    That sounds bad. You should only need the `clearTaskOnLaunch` attribute. How are you launching your app in the first place? Directly from Eclipse using the ADT tools? If so, there was a bug that meant apps weren't being launched properly from Eclipse. It's since been fixed. – Christopher Orr Apr 15 '10 at 18:55
  • yeah, directly from eclipse. but i tried with only clearTaskOnLaunch, and i coulnt get it to work... – Sephy Apr 16 '10 at 09:22
  • Hi how to add `onRestart()` method. Can you give a snippet?Thanks –  Jun 24 '11 at 12:38
  • 4
    Folks, please do not call `onCreate()` from `onRestart()`. These (creation and restart) are two different events. If you want to have them execute the same code, please do: `void myOnCreate() { ... } void onCreate(){myOnCreate();} void onRestart() {myOnCreate();}` instead. – 18446744073709551615 Oct 31 '12 at 11:44
  • @18446744073709551615: Can you explain why? – Fraggles Feb 11 '14 at 07:22
  • 1
    @Fraggles Because it makes your code ***unmaintainable***. It is generally correct when function _onRestart()_ calls _super.onRestart()_. But if you call _onCreate()_ from _onRestart()_, this perfectly sane assumption becomes wrong for your project. For example, it is also generally correct, when you realize that you need some functionality in all activities, to define your class _ActivityWithSomething_ and change _extends Activity_ to _extends ActivityWithSomething_ for all activities in the project. – 18446744073709551615 Feb 11 '14 at 09:41
  • @Fraggles, continued: But if at some point _onCreate()_ is called from from _onRestart()_, it may result in a crash that will be very difficult to debug, because when you debug code you assume that it is sane. ***Sane code should be reused, insane code should be rewritten from scratch.*** – 18446744073709551615 Feb 11 '14 at 09:41