如何以编程方式“重启”Android应用程序?

时间:2011-07-07 10:49:16

标签: android android-activity

首先,我知道不应该在Android上杀死/重启应用程序。在我的用例中,我想在服务器向客户端发送特定信息的特定情况下出厂重置我的应用程序。

用户只能使用应用程序的一个实例登录服务器(即不允许多个设备)。如果另一个实例获得“登录”锁定,那么该用户的所有其他实例都必须删除其数据(出厂重置),以保持一致性。

可以强制获取锁定,因为用户可能会删除应用程序并重新安装它,这将导致不同的实例ID,并且用户将无法再释放锁定。因此可以强行锁定。

由于这种可能性,我们需要始终检查具有锁定的具体实例。这是(几乎)对服务器的每个请求完成的。服务器可能会发送“error-lock-id”。如果检测到,则客户端应用程序必须删除所有内容。


那是用例。

我有Activity A启动登录Activity L或应用程序的主Activity B,具体取决于sharedPrefs值。在启动L或B后,它自行关闭,只有L或B运行。因此,在用户已登录的情况下,B现在正在运行。

B开始C.C为startService D调用IntentService。这导致了这个堆栈:

(A)> B> C> d

从D的onHandleIntent方法,事件发送到ResultReceiver R。

R现在通过向用户提供一个对话框来处理该事件,在该对话框中他可以选择出厂重置应用程序(删除数据库,sharedPrefs等)。

出厂重置后,我想重新启动应用程序(关闭所有活动),然后再次启动A,然后启动登录Activity L并自行完成:

(A)> →

Dialog的onClick方法如下所示:

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

这就是MyApp类:

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() {
        // ...
    }
}

问题是如果我使用FLAG_ACTIVITY_NEW_TASK活动B和C仍在运行。如果我点击登录Activity上的后退按钮,我会看到C,但我想回到主屏幕。

如果我没有设置FLAG_ACTIVITY_NEW_TASK,我会收到错误:

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?

我无法使用活动“Context,因为ServiceIntent D也可能来自AlarmManager启动的后台任务。

那我怎么能解决这个活动堆栈变成(A)> L'

29 个答案:

答案 0 :(得分:260)

您可以使用PendingIntent设置以后启动您的启动活动,然后关闭您的应用

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

答案 1 :(得分:83)

您只需致电:

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

ProcessPhoenix库中使用的


作为替代方案:

这是@Oleg Koshkin回答的一个改进版本。

如果您确实要重新启动活动,包括终止当前进程,请尝试以下代码。将它放在HelperClass或您需要的地方。

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

这也将重新初始化jni类和所有静态实例。

答案 2 :(得分:61)

Jake Wharton最近发布了他的ProcessPhoenix图书馆,它以可靠的方式完成了这项工作。你基本上只需要打电话:

ProcessPhoenix.triggerRebirth(context);

库将自动完成调用活动,终止应用程序进程并重新启动默认应用程序活动。

答案 3 :(得分:34)

IntentCompat.makeRestartActivityTask

新方法是使用 IntentCompat.makeRestartActivityTask

  

创建一个可用于重新启动应用程序任务的Intent   它的基础状态。这就像makeMainActivity(ComponentName),但也是   设置标志Intent.FLAG_ACTIVITY_NEW_TASK和   FLAG_ACTIVITY_CLEAR_TASK。

PackageManager packageManager = context.getPackageManager();
Intent intent = packageManager.getLaunchIntentForPackage(context.getPackageName());
ComponentName componentName = intent.getComponent();
Intent mainIntent = IntentCompat.makeRestartActivityTask(componentName);
context.startActivity(mainIntent);
System.exit(0);

答案 4 :(得分:26)

我稍微修改了Ilya_Gazman使用新API的答案(IntentCompat已经弃用,启动API 26)。 Runtime.getRuntime()。exit(0)似乎比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);
    context.startActivity(mainIntent);
    Runtime.getRuntime().exit(0);
}

答案 5 :(得分:26)

有一个非常好的技巧。我的问题是一些非常古老的C ++ jni库泄露了资源。在某些时候,它停止运作。用户试图退出应用程序并再次启动它 - 没有结果,因为完成一项活动与完成(或终止)该过程不同。 (顺便说一句,用户可以转到正在运行的应用程序列表并从那里停止 - 这可行,但用户只是不知道如何终止应用程序。)

如果您想观察此功能的效果,请在您的活动中添加static变量并按每个增量递增,例如按下按钮。如果退出应用程序活动,然后再次调用该应用程序,则此静态变量将保留其值。 (如果确实退出了应用程序,则会为变量分配初始值。)

(而且我必须评论为什么我不想修复错误。这个库是几十年前编写的,从那时起泄露了资源。管理层相信它总是工作< / em>。成本提供修复而不是解决方法......我想,你明白了。)

现在,我怎样才能将jni shared(a.k.a。动态,.so)库重置为初始状态? 我选择将应用程序重新启动为新进程。

技巧是System.exit()关闭当前活动,Android重新创建一个活动少的应用程序。

所以代码是:

/** This activity shows nothing; instead, it restarts the android process */
public class MagicAppRestart extends Activity {
    // Do not forget to add it to AndroidManifest.xml
    // <activity android:name="your.package.name.MagicAppRestart"/>
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        System.exit(0);
    }
    public static void doRestart(Activity anyActivity) {
        anyActivity.startActivity(new Intent(anyActivity.getApplicationContext(), MagicAppRestart.class));
    }
}

调用活动只执行代码MagicAppRestart.doRestart(this);,执行调用活动的onPause(),然后重新创建进程。不要忘记在AndroidManifest.xml中提及此活动

这种方法的优点是没有延迟。

UPD:它在Android 2.x中有效,但在Android 4中有些变化。

答案 6 :(得分:15)

我的解决方案不会重启流程/应用程序。它只允许应用程序“重启”主页活动(并解除所有其他活动)。它看起来像是重启用户,但过程是一样的。我认为在某些情况下人们希望达到这种效果,所以我只想把它留在这里。

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

答案 7 :(得分:14)

好的,我重构了我的应用程序,我不会自动完成A.我总是让它运行并通过onActivityResult事件完成它。 通过这种方式,我可以使用FLAG_ACTIVITY_CLEAR_TOP + FLAG_ACTIVITY_NEW_TASK标志来获得我想要的内容:

public class A extends Activity {

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        finish();
    }

    protected void onResume() {
        super.onResume();
        // ...
        if (loggedIn) {
            startActivityForResult(new Intent(this, MainActivity.class), 0);
        } else {
            startActivityForResult(new Intent(this, LoginActivity.class), 0);
        }
    }
}

ResultReceiver

@Override
public void onClick(DialogInterface dialog, int which) {
    MyApp.factoryReset();
    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);
}

非常感谢!

答案 8 :(得分:13)

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

答案 9 :(得分:7)

完全重新启动应用的最佳方法是重新启动它,而不仅仅是跳转到FLAG_ACTIVITY_CLEAR_TOPFLAG_ACTIVITY_NEW_TASK的活动。所以我的解决方案是从您的应用程序甚至是其他应用程序执行此操作,唯一的条件是了解应用程序包名称(例如:' 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);
}

使用重启的示例或从 appB 启动 appA

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

您可以检查应用是否正在运行:

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

注意:我知道这个答案有点偏离主题,但对某些人来说真的很有帮助。

答案 10 :(得分:5)

唯一没有触发的代码&#34;您的应用已意外关闭&#34;如下。它也是不弃用的代码,不需要外部库。它也不需要计时器。

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

答案 11 :(得分:3)

以下是使用PackageManager以通用方式重新启动应用程序的示例:

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

答案 12 :(得分:3)

尝试使用FLAG_ACTIVITY_CLEAR_TASK

答案 13 :(得分:3)

试试这个:

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

答案 14 :(得分:2)

使用FLAG_ACTIVITY_CLEAR_TASKFLAG_ACTIVITY_NEW_TASK直接启动初始屏幕。

答案 15 :(得分:2)

我不得不添加一个Handler来延迟退出:

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

答案 16 :(得分:2)

重启应用程序的最佳方法是使用finishAffinity();
由于finishAffinity();仅可用于JELLY BEAN版本,因此我们可以将ActivityCompat.finishAffinity(YourCurrentActivity.this);用于较低版本。

然后使用Intent启动第一个活动,因此代码如下所示:

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

希望有帮助。

答案 17 :(得分:1)

尝试一下:

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

答案 18 :(得分:1)

我发现它可以在API 29及更高版本上使用-出于杀死并重新启动应用程序的目的,就好像用户在未运行时启动了该应用程序一样。

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.
}

当应用中的启动器活动具有以下内容时,便完成了此操作:

<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>

我看到有评论声称需要DEFAULT类别,但我没有发现这种情况。我已经确认我的应用程序中的Application对象已重新创建,因此我认为该进程确实已经终止并重新启动。

我使用它的唯一目的是在用户启用或禁用Firebase Crashlytics崩溃报告后重新启动应用程序。根据他们的文档,该应用程序必须重新启动(进程已终止并重新创建),以使更改生效。

答案 19 :(得分:1)

我正在处理的应用程序必须让用户可以选择要显示的片段(片段在运行时动态更改)。对我来说最好的解决方案是完全重启应用程序。

所以我尝试了很多解决方案,其中没有一个对我有用,但是这个:

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

希望这会帮助别人!

答案 20 :(得分:1)

您可以使用startInstrumentation的{​​{1}}方法。您需要实现空Activity并指向清单。之后,您可以调用此方法重新启动您的应用。像这样:

Instrumentation

我动态获取Instrumentation类名,但您可以对其进行硬编码。有人喜欢这样:

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

致电try { startInstrumentation(new ComponentName(this, RebootInstrumentation.class), null, null); } catch (Throwable e) { new RuntimeException("Failed restart with Instrumentation", e); } 重新加载您的应用。阅读此方法的说明。但是如果像杀戮应用程序一样行动就不安全。

答案 21 :(得分:1)

使用:

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

我相信它从API级别16(4.1)开始工作。

答案 22 :(得分:0)

使用Process Phoenix library。您要重新启动的活动名为“ A”。

Java风格

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

科特林风味

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

答案 23 :(得分:0)

this的Kotlin版本答案:

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

答案 24 :(得分:0)

在MainActivity调用restartActivity方法中:

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

答案 25 :(得分:0)

迈克彭斯的《替代答案》需要对我的情况进行一些更改。 https://stackoverflow.com/a/22345538/12021422 我可以修改Mikepenz的答案的主要功劳。

这是为我工作的即插即用静态功能。

只需传递应用程序上下文,此函数将处理重启。

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

答案 26 :(得分:0)

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

答案 27 :(得分:-1)

您可以像这样重新启动当前活动:

片段:

activity?.recreate()

活动:

recreate()

答案 28 :(得分:-2)

嘿兄弟,如果您想通过单击按钮重新启动您的应用程序,请编写此代码并记住使用您的按钮名称更改重置,如果您将在代码段中运行它,它将不起作用,因为我选择了javascript,它是java语言

public class Printer {
    private String name;

    public void setName(String name) {
        this.name = name;
    }

    public void print() {
        printString(name);
    }

    private void printString(String s) {
        System.out.println(s + " (" + s.length() + ")");
    }

    public static void main(String[] args) {
        Printer printer = new Printer();
        printer.print();
    }
}