首先,我知道在Android上不应该真正地关闭/重启应用程序。在我的用例中,我想在服务器向客户机发送一条特定信息的特定情况下对应用程序进行工厂重置。

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

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

由于这种强制的可能性,我们需要始终检查一个具体实例是否拥有锁。这是在(几乎)对服务器的每个请求上完成的。服务器可能会发送一个“错误的锁定id”。如果检测到这种情况,客户机应用程序必须删除所有内容。


这就是用例。

我有一个活动A,启动登录活动L或应用程序的主活动B,这取决于一个sharedPrefs值。在启动L或B之后,它关闭自己,以便只有L或B在运行。在用户已经登录的情况下,B正在运行。

B启动C, C调用startService为IntentService服务。

(a) > b > c > d

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

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

在工厂重置后,我想重新启动应用程序(关闭所有活动),只启动A,然后启动登录活动L并完成自己:

(a) > l

对话框的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仍在运行。如果我点击登录活动的返回按钮,我看到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?

我不能使用活动的上下文,因为ServiceIntent D也可能从一个由AlarmManager启动的后台任务中调用。

那么我如何解决这个问题,使活动堆栈变成(A) >l呢?


当前回答

我的解决方案没有重新启动进程/应用程序。它只允许应用程序“重启”home活动(并解散所有其他活动)。对用户来说,这看起来像是重新启动,但过程是一样的。我认为在某些情况下,人们想要达到这种效果,所以我只是在这里供大家参考。

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

其他回答

嘿,兄弟,如果你想重新启动你的应用程序点击一个按钮,所以写这段代码,记得改变重置与你的按钮的名称,如果你将运行这段代码,它将无法工作,因为我已经选择了javascript,它是java语言

重置。setOnClickListener(new View.OnClickListener() { @Override onClick(查看v) { 完成(); startActivity (getIntent ()); } });

Jake Wharton最近发布了他的ProcessPhoenix库,它以一种可靠的方式做到了这一点。你基本上只需要调用:

ProcessPhoenix.triggerRebirth(context);

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

应用延迟重启

startDelay启动延迟时间(单位:毫秒)

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

可以使用Activity的startInstrumentation方法。您需要在manifest中实现空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);
}

我动态地获得Instrumentation类名,但是你可以硬编码它。有些是这样的:

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

调用startInstrumentation make reload你的应用程序。阅读这个方法的描述。但如果像杀人程序一样,它可能是不安全的。

尝试使用FLAG_ACTIVITY_CLEAR_TASK