Android - 从广播接收器启动应用程序

14

我希望广播接收器可以以以下方式启动我的应用:

  1. 如果应用程序不在前台或后台,则启动应用程序,就好像从启动器启动一样。

  2. 如果应用程序在后台,则将其带到前台,并保持其上次的状态。

  3. 如果应用程序在前台,则不执行任何操作。

以下是我的代码:

@Override
public void onReceive(Context context, Intent intent) {
        Intent launch_intent = new Intent("android.intent.action.MAIN");
        launch_intent.setComponent(new ComponentName("com.example.helloworld","com.example.helloworld.MainActivity"));
        launch_intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
        launch_intent.addCategory(Intent.CATEGORY_LAUNCHER);
        launch_intent.putExtra("some_data", "value");
        context.startActivity(launch_intent);
}

MainActivity是我的根活动。正如我所说的,如果应用程序已经在运行,则只需将其移到前台而不更改其状态。如果有一些活动在MainActivity之上,则保持原状。

大多数情况下,上述代码工作得很好,但有时候我注意到当它从后台调回时,应用程序被重新启动(或状态被重置---根活动又回到了顶部)。

我应该使用什么代码?任何帮助都将不胜感激!


ActivityManager.getAppTasks()AppTask.moveToFront()似乎是不错的选择,但这些仅适用于API 21及更高版本。 - Karakuri
@Karakuri,有更简单的方法可以实现这个功能。通常情况下,如果你只是在“启动Intent”上调用startActivity(一个启动根ActivityIntent,并在新任务中启动),这将启动应用程序(如果它没有运行)或将后台中的现有任务带到前台。 - David Wasser
4个回答

12

你不需要编写所有那些代码。你可以使用“启动Intent”,如下所示:

PackageManager pm = context.getPackageManager();
Intent launchIntent = pm.getLaunchIntentForPackage("com.example.helloworld");
launchIntent.putExtra("some_data", "value");
context.startActivity(launchIntent);
然而,你的代码应该也是可以工作的。 如果你说这个代码大部分时间都可以运行,那么你可能会在这些情况下看到一个旧的、恶性的Android bug。这种情况发生在你第一次从安装程序或IDE(如Eclipse、Android Studio等)直接启动应用程序时。你应该始终直接从HOME屏幕或已安装应用程序列表中第一次启动你的应用程序。有关这个令人沮丧的Android bug的更多信息,请参见https://dev59.com/Muo6XIcBkEYKwwoYNBln#16447508

不设置任何标志位,我该如何获取额外的数据?我不应该使用FLAG_ACTIVITY_SINGLE_TOP,并为MainActivity实现onNewIntent方法吗? - Shawn
1
如果您的应用程序已经在运行,则此操作将仅将其置于前台。它不会调用onNewIntent()。如果您需要在此情况下的“额外信息”,则需要采取不同的方法。请查看我对此问题的回答,其中我展示了如何使用“不执行任何操作的活动”来实现此目的。 - David Wasser
你的意思是要发送额外的数据到NotificationActivity并在那里执行一些操作,然后关闭它吗?我该如何检查应用程序是否正在运行(前台或后台)? - Shawn
谢谢!这已经很有帮助了。但是我如何从NotificationActivity中知道应用程序是否已经在运行? - Shawn
NotificationActivity()onCreate() 方法中,您可以调用 isTaskRoot() 方法。如果返回值为 true,那么应用程序之前没有运行(因为 NotificationActivity 是任务中唯一的 Activity)。否则,应用程序已经在运行,并且 NotificationActivity 在任务中的其他活动之上。 - David Wasser
显示剩余4条评论

10

由于您需要的行为如下:

1)如果应用程序不在前台或后台,请将其启动,就好像是从启动器启动它一样。

2)如果应用程序在后台运行,则将其带到前台并保持其上次状态。

3)如果应用程序在前台运行,则不执行任何操作。

请考虑:

@Override
public void onReceive(Context context, Intent intent) {

    Intent startIntent = context
            .getPackageManager()
            .getLaunchIntentForPackage(context.getPackageName());

    startIntent.setFlags(
                    Intent.FLAG_ACTIVITY_REORDER_TO_FRONT |
                    Intent.FLAG_ACTIVITY_NEW_TASK |
                    Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
    );
    context.startActivity(startIntent);
}

1
我认为它应该是被选中的答案。 - letroll
我可能使用不当,但如果持续接收广播,它会不断启动应用程序。在使用时要小心。 - Santhosh

3
@Override
public void onReceive(Context context, Intent intent) {
    Intent launch_intent = new  Intent(context, MainActivity.class);
    launch_intent.setComponent(new ComponentName("com.example.helloworld","com.example.helloworld.MainActivity");
    launch_intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP |INTENT.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
    launch_intent.putExtra("some_data", "value");
    launch_intent.addCategory(Intent.CATEGORY_LAUNCHER);
    context.startActivity(launch_intent);
}

这很简单,但是如果不知道正确的方法,当您尝试从意图中获取额外的数据时,通常会遇到java空指针异常。

使用onNewIntent()方法接收额外的数据。如果想知道更多,请在下面评论。

编辑: 尝试以下操作。但我不明白的是,我给你的第一段代码应该可以单独工作。它一直对我有效。您是否确保已复制我给您的第一段代码并且粘贴时没有进行任何更改?

编辑2: 如果这不起作用,请将标志设置为clearTaskOnLaunch而不是INTENT.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED


谢谢。已经接近成功了。通过你的代码和onNewIntent,我可以在MainActivity没有其他活动时获取额外的数据。如果我将应用程序放到后台并在MainActivity上方有一些活动,则单击通知会将应用程序带回(另一个活动仍然在MainActivity上方),但不会调用onNewIntent。我想要保留在MainActivity上方的活动。如何才能获得额外的数据? - Shawn
我尝试过了。当应用程序在顶部有其他活动时,MainActivity的onNewIntent不会被调用。 - Shawn
你的 Manifest 文件中 MainActivity 是否被声明为你的类别启动器? - KISHORE_ZE
是的,它被声明为类别启动器。我认为clearTaskOnLaunch会将应用程序重置到根活动,但这不是我想要的。如果在根活动上方还有其他活动,那么根活动的onNewIntent不会立即被调用,对吗? - Shawn
在您的意图中,如果您只指定了主要活动,则只应启动主要活动,而不是其他活动。这就是为什么我不明白为什么它不起作用。 - KISHORE_ZE
显示剩余9条评论

0
假设您已经了解了BroadcastReceiver,您只需要像通常在 onReceive 上那样进行启动:因此它将看起来像这样。
@Override
public void onReceive(Context context, Intent intent) {
    Intent launch_intent = new Intent("android.intent.action.MAIN");
    launch_intent.putExtra("some_data", "value");
    tiapp.startActivity(launch_intent);
}

如果之前已经启动过,它将只是恢复该活动,否则它将启动一个新的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接