Android 防止两次启动GcmTaskService

Android 防止两次启动GcmTaskService,android,google-play-services,Android,Google Play Services,我创建了一个非常简单的服务,用于更新服务器上的用户位置: public class LocationSchedulerService extends GcmTaskService { @Override public int onRunTask(TaskParams taskParams) { // Update to server stuff return GcmNetworkManager.RESULT_SUCCESS; } }

我创建了一个非常简单的服务,用于更新服务器上的用户位置:

public class LocationSchedulerService extends GcmTaskService {

    @Override
    public int onRunTask(TaskParams taskParams) {
        // Update to server stuff

        return GcmNetworkManager.RESULT_SUCCESS;
    }
}
我创建了一个简单的BootBroadcastReceiver,以便在设备启动时启动服务:

PeriodicTask task = new PeriodicTask.Builder()
        .setTag("LocationSchedulerService")
        .setService(LocationSchedulerService.class)
        .setPeriod(LOCATION_UPDATE_PERIOD * 60)
        .setFlex(LOCATION_UPDATE_FLEX * 60)
        .setPersisted(false)
        .setRequiredNetwork(Task.NETWORK_STATE_CONNECTED)
        .setRequiresCharging(false)
        .setUpdateCurrent(true)
        .build();

GcmNetworkManager.getInstance(context).schedule(task);
现在我的问题是: 因为不可能知道用户何时安装了软件包,所以我也想在用户启动应用程序时启动此任务。但是如何防止任务运行两次呢


我看过的文件,但我不确定的功能。这是否意味着当前正在运行的服务将被取消,或者这正是我想要的?

从文档中可以看出,调用
setUpdateCurrent(true)
将使用相同的标记更新
PeriodicTask
的调度约束

可选设置程序,用于指定此任务是否应覆盖具有相同标记的任何先前存在的任务。这默认为false,这意味着新任务不会覆盖现有任务


此外,您还可以在计划新任务之前取消您的
任务
,如您所述,这就是引入setUpdateCurrent的原因-应用程序需要一种方法“仅在任务不存在时计划任务”

但是“如何防止任务运行两次”是什么意思?您正在计划PeriodicTask,这意味着任务将每隔(位置更新周期*60)秒执行一次

听起来您需要的是默认的setUpdateCurrent=false,您可以在启动完成时以及在应用程序的onCreate()中安排周期任务

如果您担心的是,在第一次启动时,您希望立即更新位置,然后默认为每个位置更新周期*60秒,那么您可以在onCreate中编写代码: 检查第一次引导(可能写入共享的\u prefs文件,如果该值不存在,则您知道这是第一次引导) 如果是第一次启动,则计划在下一分钟执行一个特殊的OneoffTask。给这个OneoffTask一个特殊的标签,比如“LocationSchedulerService:first\u boot”

然后在您的位置SchedulerService扩展GcmTaskService:

public int onRunTask{
    if (tag.equals("LocationSchedulerService:first_boot")) {
        performLocationUpdate();
        // Now that you've done the one time update, fall back to
        // your original schedule

        PeriodicTask task = new PeriodicTask.Builder()
            .setTag("LocationSchedulerService")
            .setService(LocationSchedulerService.class)
            .setPeriod(LOCATION_UPDATE_PERIOD * 60)
            .setFlex(LOCATION_UPDATE_FLEX * 60)
            .setPersisted(false)
            .setRequiredNetwork(Task.NETWORK_STATE_CONNECTED)  // not needed, default
            .setRequiresCharging(false)  // not needed, default
            .setUpdateCurrent(true) // not needed, you know this is 1st time
            .build();

            GcmNetworkManager.getInstance(context).schedule(task);
    } else if tag.equals("LocationSchedulerService") {
        performLocationUpdate();
    } else {
        // error
    }
顺便说一下,你不需要一个开机完成的接收器。GcmNetworkManager的思想是通过设置persisted=true来避免这种情况。这样,您就知道您的任务将在重新启动期间持久化。
通常只需在onCreate中安排一次就足够了。

因为您的目标是始终运行
gcmtasksservice
,包括通过重新启动,所以只需执行
setpersistend(true)
,而不是问题中的示例代码中的false

从:

public PeriodicTask.Builder setPersisted(布尔值isPersisted)

可选的setter,用于指定此任务是否应在重新启动期间持久化。对于定期任务,此默认值为true。调用者必须持有android.Manifest.permission.RECEIVE\u BOOT\u COMPLETED权限,否则将忽略此setter

因此,不必担心制作自己的BootBroadcastReceiver,只需添加引导权限即可


因为主要问题是防止同时运行
gcmtasksservice
。。这可以通过为任务使用相同的标记来实现。默认情况下,如果任务(同名)已在运行,则将发生。通过执行
setUpdateCurrent(true)
,调用
schedule()
时任务的参数将被更新/替换


来源:

谢谢,我会在每次应用程序启动时再次安排作业(使用setUpdateCurrent),有一点副作用是每次都会将下一次执行时间重置回我的位置\u更新\u周期。但是这不是什么大问题。Philip,如果你这样做,那么你应该设置DateCurrent(false)(实际上这是默认设置)。这样做的目的是,每次应用程序启动时,您都可以调用schedule(),但不会将时间推到最后。这正是setter存在的原因。如果任务未计划(首次安装),则会将其插入。谢谢您的完整回答。现在我删除了BOOT_RECEIVED permission和receiver。@PhilipGiuliani重新启动后,GcmNetworkManager仍需要BOOT_RECEIVED permission才能继续执行任务。