Stuck
Stuck

Reputation: 12302

How do I programmatically "restart" an Android app?

Firstly, I know that one should not really kill/restart an application on Android. In my use case, I want to factory-reset my application in a specific case where a server sends a piece of specific information to the client.

The user can only be logged in on the server with ONE instance of the application (i.e. multiple devices are not allowed). If another instance gets that "logged-in"-lock then all other instances of that user have to delete their data (factory-reset), to maintain consistency.

It is possible to forcibly get the lock because the user might delete the app and reinstall it which would result in a different instance-id and the user would not be able to free the lock anymore. Therefore it is possible to forcibly get the lock.

Because of that force-possibility, we need to always check in a concrete instance that it has the lock. That is done on (almost) each request to the server. The server might send a "wrong-lock-id". If that is detected, the client application must delete everything.


That was the use-case.

I have an Activity A that starts the Login Activity L or the app's main Activity B depending on a sharedPrefs value. After starting L or B it closes itself so that only L or B is running. So in the case that the user is logged in already B is running now.

B starts C. C calls startService for the IntentService D. That results in this stack:

(A) > B > C > D

From the onHandleIntent method of D, an event is sent to a ResultReceiver R.

R now handles that event by providing the user a dialog where he can choose to factory-reset the application (delete the database, sharedPrefs, etc.)

After the factory-reset I want to restart the application (to close all activities) and only start A again which then launches the login Activity L and finishes itself:

(A) > L

The Dialog's onClick-method looks like this:

@Override
public void onClick(DialogInterface dialog, int which) {

    // Will call onCancelListener
    MyApplication.factoryReset(); // (Deletes the database, clears sharedPrefs, etc.)
    Intent i = new Intent(MyApp.getContext(), A.class);
    i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    MyApp.getContext().startActivity(i);
}

And that's the MyApp class:

public class MyApp extends Application {
    private static Context context;

    @Override
    public void onCreate() {
        super.onCreate();
        context = getApplicationContext();
    }

    public static Context getContext() {
        return context;
    }

    public static void factoryReset() {
        // ...
    }
}

The problem is if I use the FLAG_ACTIVITY_NEW_TASK the Activities B and C are still running. If I hit the back button on the login Activity I see C, but I want to go back to the home screen.

If I do not set the FLAG_ACTIVITY_NEW_TASK I get the error:

07-07 12:27:12.272: ERROR/AndroidRuntime(9512): android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity  context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?

I cannot use the Activities' Context, because the ServiceIntent D might also be called from a background task which is started by the AlarmManager.

So how could I solve this to the activity stack becoming (A) > L?

Upvotes: 352

Views: 391240

Answers (30)

Anoop M Maddasseri
Anoop M Maddasseri

Reputation: 10559

Here’s the working code for scheduling an app restart, which functions as expected on devices running Android 12 (API Level 31) and below. This code has not been tested on devices running versions above API Level 31

private const val PENDING_INTENT_ID = 223344
private const val RESTART_DELAY_MS = 100L  // 100 milliseconds

    // Schedules an app restart by creating a PendingIntent that will trigger the app's launch after a short delay.
    fun scheduleAppRestart(context: Context) {
        val launchIntent = createAppLaunchIntent(context)
        launchIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
        Timber.d("App restart intent: $launchIntent")

        val pendingIntent = PendingIntent.getActivity(
            context,
            PENDING_INTENT_ID,
            launchIntent,
            PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE
        )

        val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
        alarmManager.set(
            AlarmManager.RTC, System.currentTimeMillis() + RESTART_DELAY_MS, pendingIntent
        )
    }

    // Creates an Intent to launch the app's main activity or default activity, considering Android TV (Leanback) support.
    private fun createAppLaunchIntent(context: Context): Intent {
        val packageName = context.packageName
        val packageManager = context.packageManager

        // Try getting the Leanback launch intent for Android TV apps
        val launchIntent =
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && packageManager.hasSystemFeature(
                    PackageManager.FEATURE_LEANBACK
                )
            ) {
                packageManager.getLeanbackLaunchIntentForPackage(packageName)
            } else {
                packageManager.getLaunchIntentForPackage(packageName)
            }

        return launchIntent ?: throw IllegalStateException(
            "Unable to determine default activity for $packageName. Does an activity specify the DEFAULT category in its intent filter?"
        )
    }

Usage:

if (isAppInForeground) {
    scheduleAppRestart(applicationContext)  // Schedule app restart if it's in the foreground
}

exitProcess(0) // exit process optionally

Upvotes: 0

omega_mi
omega_mi

Reputation: 718

For my flutter apps, this is the only method works https://github.com/gabrimatic/restart_app/blob/master/android/src/main/kotlin/gabrimatic/info/restart/RestartPlugin.kt. I tried solutions from answer but after exit the app, the apps not reopen back. Somebody already provide solutions using makeRestartActivityTask but still doesn't works, i guess it because how the context & component fetch from.

import android.content.Intent

private fun restartApp() {
    context.startActivity(
        Intent.makeRestartActivityTask(
            context.packageManager.getLaunchIntentForPackage(
                context.packageName
            ))!!.component
        )
    )
    Runtime.getRuntime().exit(0)
}

I decided to did'nt use the plugin because it's not up to date, while I regularly update the flutter version to the latest.

Set the method call here:

private val _channel = "myApp/channel"

override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
    super.configureFlutterEngine(flutterEngine)
    MethodChannel(flutterEngine.dartExecutor.binaryMessenger, _channel).setMethodCallHandler {
        call, result ->
        when (call.method) {
            "restartApp" -> {
                result.success(restartApp())
            }
            else -> {
                result.notImplemented()
            }
        }
    }
}

Trigger it from flutter:

void _restartApp() {
    const MethodChannel('myApp/channel').invokeMethod<void>('restartApp');
}

Upvotes: 0

ΓDΛ
ΓDΛ

Reputation: 11110

For Kotlin - 2023 Edition

fun Context.restartApplication() {
    val intent = packageManager.getLaunchIntentForPackage(packageName)
    val componentName = intent?.component
    val mainIntent = Intent.makeRestartActivityTask(componentName)
    startActivity(mainIntent)
    Runtime.getRuntime().exit(0)
}

Upvotes: 8

android_dev
android_dev

Reputation: 4188

I have slightly modified Ilya_Gazman answer to use new APIs (IntentCompat is deprecated starting API 26). Runtime.getRuntime().exit(0) seems to be better than System.exit(0).

 public static void triggerRebirth(Context context) {
    PackageManager packageManager = context.getPackageManager();
    Intent intent = packageManager.getLaunchIntentForPackage(context.getPackageName());
    ComponentName componentName = intent.getComponent();
    Intent mainIntent = Intent.makeRestartActivityTask(componentName);
    // Required for API 34 and later
    // Ref: https://developer.android.com/about/versions/14/behavior-changes-14#safer-intents
    mainIntent.setPackage(context.getPackageName());
    context.startActivity(mainIntent);
    Runtime.getRuntime().exit(0);
}

Upvotes: 147

bayram.cicek
bayram.cicek

Reputation: 343

Kotlin version of this answer:

val intent = Intent(this, YourActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
startActivity(intent)
Runtime.getRuntime().exit(0)

Upvotes: 4

mingganglee
mingganglee

Reputation: 306

This code passed the Android 8-13 test

public void restartApp() {
    Intent i = getBaseContext().getPackageManager().getLaunchIntentForPackage( getBaseContext().getPackageName() );  
    startActivity(Intent.makeRestartActivityTask(i.getComponent()));  
    Runtime.getRuntime().exit(0);
}

Upvotes: 7

Muhaiminur Rahman
Muhaiminur Rahman

Reputation: 3152

I got this way.

Intent i = getBaseContext().getPackageManager().getLaunchIntentForPackage( 
 getBaseContext().getPackageName() );
 i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
 startActivity(i);
 finish();

Upvotes: 2

Osama Ibrahim
Osama Ibrahim

Reputation: 1021

val i = baseContext.packageManager.getLaunchIntentForPackage(baseContext.packageName)
i!!.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
startActivity(i)
finish()

Upvotes: 0

Richard Kamere
Richard Kamere

Reputation: 799

Apply delay restart

startDelay Startup delay (in milliseconds)

 public static void reStartApp(Context context, long startDelay) {
    //Obtain the startup Intent of the application with the package name of the application
    Intent intent = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());
    PendingIntent restartIntent = PendingIntent.getActivity(context.getApplicationContext(), -1, intent, PendingIntent.FLAG_CANCEL_CURRENT);

    AlarmManager mgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    if (mgr != null) {
        mgr.set(AlarmManager.RTC, System.currentTimeMillis() + startDelay, restartIntent);
    }
}

Upvotes: 0

Kumar Santanu
Kumar Santanu

Reputation: 701

Still Working Now

 public void resetApplication() {
    Intent resetApplicationIntent = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());
    if (resetApplicationIntent != null) {
        resetApplicationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
    }
    context.startActivity(resetApplicationIntent);
    ((Activity) context).overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
}

Upvotes: 7

hey bro if you want to restart your app with the click of a button so write this code and remember to change reset with the name of your button and if you will run this in the snippet it will not work because I have chosen javascript and it is java language

reset.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            finish();

                            startActivity(getIntent());
                        }
                    });

Upvotes: -3

Gentle dude
Gentle dude

Reputation: 29

fun triggerRestart(context: Activity) {
    val intent = Intent(context, MainActivity::class.java)
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
    context.startActivity(intent)
    if (context is Activity) {
        (context as Activity).finish()
    }
    Runtime.getRuntime().exit(0)
}

Upvotes: 2

Rahul Shyokand
Rahul Shyokand

Reputation: 1505

Mikepenz's Alternative Answer needed some changes in my case. https://stackoverflow.com/a/22345538/12021422 Major Credits to Mikepenz's Answer which I could modify.

Here is the Plug and Play static function that worked for me.

Just pass the Context of Application and this function will handle the restart.

    public static void doRestart(Context c) {
        try {
            // check if the context is given
            if (c != null) {
                // fetch the package manager so we can get the default launch activity
                // (you can replace this intent with any other activity if you want
                PackageManager pm = c.getPackageManager();
                // check if we got the PackageManager
                if (pm != null) {
                    // create the intent with the default start activity for your application
                    Intent mStartActivity = pm.getLaunchIntentForPackage(c.getPackageName());
                    if (mStartActivity != null) {
                        mStartActivity.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                        
                        c.getApplicationContext().startActivity(mStartActivity);
                        // kill the application
                        System.exit(0);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            Log.e("restart", "Could not Restart");
        }
    }

Upvotes: -1

farhad.kargaran
farhad.kargaran

Reputation: 2373

in MainActivity call restartActivity Method:

public static void restartActivity(Activity mActivity) {
    Intent mIntent = mActivity.getIntent();
    mActivity.finish();
    mActivity.startActivity(mIntent);
}

Upvotes: -3

Ilya Gazman
Ilya Gazman

Reputation: 32271

IntentCompat.makeMainSelectorActivity - Last tested on 11/2020

The app will be restored with the launcher activity and the old process will be killed.

Works from Api 15.

public static void restart(Context context){
    Intent mainIntent = IntentCompat.makeMainSelectorActivity(Intent.ACTION_MAIN, Intent.CATEGORY_LAUNCHER);
    mainIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    context.getApplicationContext().startActivity(mainIntent);
    System.exit(0);
}

Upvotes: 49

Yijun Li
Yijun Li

Reputation: 57

Directly start the initial screen with FLAG_ACTIVITY_CLEAR_TASK and FLAG_ACTIVITY_NEW_TASK.

Upvotes: 1

Raymond Chenon
Raymond Chenon

Reputation: 12712

With the Process Phoenix library. The Activity you want to relaunch is named "A".

Java flavor

// Java
public void restart(){
    ProcessPhoenix.triggerRebirth(context);
}

Kotlin flavor

// kotlin
fun restart() {
    ProcessPhoenix.triggerRebirth(context)
}

Upvotes: 0

Mark Peters
Mark Peters

Reputation: 495

I've found that this works on API 29 and later - for the purpose of killing and restarting the app as if the user had launched it when it wasn't running.

public void restartApplication(final @NonNull Activity activity) {
   // Systems at 29/Q and later don't allow relaunch, but System.exit(0) on
   // all supported systems will relaunch ... but by killing the process, then
   // restarting the process with the back stack intact. We must make sure that
   // the launch activity is the only thing in the back stack before exiting.
   final PackageManager pm = activity.getPackageManager();
   final Intent intent = pm.getLaunchIntentForPackage(activity.getPackageName());
   activity.finishAffinity(); // Finishes all activities.
   activity.startActivity(intent);    // Start the launch activity
   System.exit(0);    // System finishes and automatically relaunches us.
}

That was done when the launcher activity in the app has this:

<intent-filter>
    <action android:name="android.intent.action.VIEW"/>
    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

I've seen comments claiming that a category of DEFAULT is needed, but I haven't found that to be the case. I have confirmed that the Application object in my app is re-created, so I believe that the process really has been killed and restarted.

The only purpose for which I use this is to restart the app after the user has enabled or disabled crash reporting for Firebase Crashlytics. According to their docs, the app has to be restarted (process killed and re-created) for that change to take effect.

Upvotes: 30

Hussein Nasereddine
Hussein Nasereddine

Reputation: 224

My best way to restart application is to use finishAffinity();
Since, finishAffinity(); can be used on JELLY BEAN versions only, so we can use ActivityCompat.finishAffinity(YourCurrentActivity.this); for lower versions.

Then use Intent to launch first activity, so the code will look like this:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
    finishAffinity();
    Intent intent = new Intent(getApplicationContext(), YourFirstActivity.class);
    startActivity(intent);
} else {
    ActivityCompat.finishAffinity(YourCurrentActivity.this);
    Intent intent = new Intent(getApplicationContext(), YourFirstActivity.class);
    startActivity(intent);
}

Hope it helps.

Upvotes: 6

user10086821
user10086821

Reputation:

You can restart your current activity like this:

Fragment :

activity?.recreate()

Activity :

recreate()

Upvotes: -6

Haskell McRavin
Haskell McRavin

Reputation: 641

The only code that did not trigger "Your app has closed unexpectedly" is as follows. It's also non-deprecated code that doesn't require an external library. It also doesn't require a timer.

public static void triggerRebirth(Context context, Class myClass) {
    Intent intent = new Intent(context, myClass);
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
    context.startActivity(intent);
    Runtime.getRuntime().exit(0);
}

Upvotes: 36

veeson
veeson

Reputation: 195

try this:

Intent intent = getPackageManager().getLaunchIntentForPackage(getPackageName());
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);

Upvotes: 0

yongsunCN
yongsunCN

Reputation: 766

My solution doesn't restart the process/application. It only lets the app "restart" the home activity (and dismiss all other activities). It looks like a restart to users, but the process is the same. I think in some cases people want to achieve this effect, so I just leave it here FYI.

public void restart(){
    Intent intent = new Intent(this, YourHomeActivity.class);
    this.startActivity(intent);
    this.finishAffinity();
}

Upvotes: 39

Choletski
Choletski

Reputation: 7525

The best way to fully restart an app is to relaunch it, not just to jump to an activity with FLAG_ACTIVITY_CLEAR_TOP and FLAG_ACTIVITY_NEW_TASK. So my solution is to do it from your app or even from another app, the only condition is to know the app package name (example: 'com.example.myProject')

 public static void forceRunApp(Context context, String packageApp){
    Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(packageApp);
    launchIntent.setFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS | Intent.FLAG_ACTIVITY_NEW_TASK);
    context.startActivity(launchIntent);
}

Example of usage restart or launch appA from appB:

forceRunApp(mContext, "com.example.myProject.appA");

You can check if the app is running:

 public static boolean isAppRunning(Context context, String packageApp){
    ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    List<ActivityManager.RunningAppProcessInfo> procInfos = activityManager.getRunningAppProcesses();
    for (int i = 0; i < procInfos.size(); i++) {
        if (procInfos.get(i).processName.equals(packageApp)) {
           return true;
        }
    }
    return false;
}

Note: I know this answer is a bit out of topic, but it can be really helpful for somebody.

Upvotes: 9

user317033
user317033

Reputation:

Use:

navigateUpTo(new Intent(this, MainActivity.class));

It works starting from API level 16 (4.1), I believe.

Upvotes: 1

Andy7229082
Andy7229082

Reputation: 17

I had to add a Handler to delay the exit:

 mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 200, mPendingIntent);
        final Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                Runtime.getRuntime().exit(0);
            }
        }, 100);

Upvotes: 0

hzitoun
hzitoun

Reputation: 5832

The application I'm working on has to give the user the possibility to choose which fragments to display (fragments are dynamically changed at run-time). The best solution for me was to restart completely the application.

So I tried plenty of solutions and none of them has worked for me, but this:

final Intent mStartActivity = new Intent(SettingsActivity.this, Splash.class);
final int mPendingIntentId = 123456;
final PendingIntent mPendingIntent = PendingIntent.getActivity(SettingsActivity.this, mPendingIntentId, mStartActivity,
                    PendingIntent.FLAG_CANCEL_CURRENT);
final AlarmManager mgr = (AlarmManager) SettingsActivity.this.getSystemService(Context.ALARM_SERVICE);
mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, mPendingIntent);
this.finishAffinity(); //notice here
Runtime.getRuntime().exit(0); //notice here

Hoping that is going to help someone else!

Upvotes: 1

Enyby
Enyby

Reputation: 4430

You can use startInstrumentation method of Activity. You need implement empty Instrumentation and pointed in manifest. After that you can call this method for restart your app. Like this:

try {           
    InstrumentationInfo info = getPackageManager().queryInstrumentation(getPackageName(), 0).get(0);
    ComponentName component = new ComponentName(this, Class.forName(info.name));
    startInstrumentation(component, null, null);
} catch (Throwable e) {             
    new RuntimeException("Failed restart with Instrumentation", e);
}

I get Instrumentation class name dynamically but you can hardcode it. Some like this:

try {           
    startInstrumentation(new ComponentName(this, RebootInstrumentation.class), null, null); 
} catch (Throwable e) {             
    new RuntimeException("Failed restart with Instrumentation", e);
}

Call startInstrumentation make reload of your app. Read description of this method. But it can be not safe if acting like kill app.

Upvotes: 1

mikepenz
mikepenz

Reputation: 12868

You can simply call:

public static void triggerRebirth(Context context, Intent nextIntent) {
    Intent intent = new Intent(context, YourClass.class);
    intent.addFlags(FLAG_ACTIVITY_NEW_TASK);
    intent.putExtra(KEY_RESTART_INTENT, nextIntent);
    context.startActivity(intent);
    if (context instanceof Activity) {
      ((Activity) context).finish();
    }

    Runtime.getRuntime().exit(0);
}

Which is used in the ProcessPhoenix library


As an alternative:

Here's a bit improved version of @Oleg Koshkin answer.

If you really want to restart your activity including a kill of the current process, try following code. Place it in a HelperClass or where you need it.

public static void doRestart(Context c) {
        try {
            //check if the context is given
            if (c != null) {
                //fetch the packagemanager so we can get the default launch activity 
                // (you can replace this intent with any other activity if you want
                PackageManager pm = c.getPackageManager();
                //check if we got the PackageManager
                if (pm != null) {
                    //create the intent with the default start activity for your application
                    Intent mStartActivity = pm.getLaunchIntentForPackage(
                            c.getPackageName()
                    );
                    if (mStartActivity != null) {
                        mStartActivity.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                        //create a pending intent so the application is restarted after System.exit(0) was called. 
                        // We use an AlarmManager to call this intent in 100ms
                        int mPendingIntentId = 223344;
                        PendingIntent mPendingIntent = PendingIntent
                                .getActivity(c, mPendingIntentId, mStartActivity,
                                        PendingIntent.FLAG_CANCEL_CURRENT);
                        AlarmManager mgr = (AlarmManager) c.getSystemService(Context.ALARM_SERVICE);
                        mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, mPendingIntent);
                        //kill the application
                        System.exit(0);
                    } else {
                        Log.e(TAG, "Was not able to restart application, mStartActivity null");
                    }
                } else {
                    Log.e(TAG, "Was not able to restart application, PM null");
                }
            } else {
                Log.e(TAG, "Was not able to restart application, Context null");
            }
        } catch (Exception ex) {
            Log.e(TAG, "Was not able to restart application");
        }
    }

This will also reinitialize jni classes and all static instances.

Upvotes: 130

TBieniek
TBieniek

Reputation: 4937

Jake Wharton recently published his ProcessPhoenix library, which does this in a reliable way. You basically only have to call:

ProcessPhoenix.triggerRebirth(context);

The library will automatically finish the calling activity, kill the application process and restart the default application activity afterwards.

Upvotes: 91

Related Questions