防止两次启动GcmTaskService

时间:2015-06-03 12:03:00

标签: android google-play-services

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

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的文档,但我不确定功能性。这是否意味着当前正在运行的服务将被取消,或者它正是我想要的东西?

3 个答案:

答案 0 :(得分:4)

从文档中看来,调用setUpdateCurrent(true)似乎会更新PeriodicTask的日程安排限制,并使用相同的标记。

  

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

另外,您可以在使用GcmNetworkManager.cancelTask()

安排新的Task之前取消ImpactEntity

答案 1 :(得分:3)

你所描述的是为什么引入了setUpdateCurrent - 应用程序想要一种方法“只安排他们的任务,如果它还不存在”

但你怎么说“我怎么防止任务运行两次”?您正在安排PeriodicTask,这意味着该任务将每隔(LOCATION_UPDATE_PERIOD * 60)秒执行。

听起来默认的setUpdateCurrent = false就是您想要的,并且您在应用程序的onCreate()中的BOOT_COMPLETED 上安排了PeriodicTask。

如果您担心首次启动时要立即更新位置,然后默认为每个LOCATION_UPDATE_PERIOD * 60秒,则可以将onCreate中的代码写入:  检查第一次启动(可能写入shared_prefs文件,如果该值不存在,那么你知道它是第一次启动)     如果第一次启动,安排一个特殊的OneoffTask在下一分钟执行。给这个OneoffTask一个特殊的标签,比如“LocationSchedulerService:first_boot”

然后在您的LocationSchedulerService中扩展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
    }

顺便说一下,你不需要一个BOOT_COMPLETED接收器。 GcmNetworkManager的想法是允许您通过设置persisted = true来避免这种情况。这样您就知道您的任务将在重新启动后保持不变。 通常只需在onCreate中安排一次就足够了。

答案 2 :(得分:1)

由于您的目标是始终运行GcmTaskService,包括重新启动,您需要做的只是setPersisted(true),而不是问题示例代码中的错误。

来自docs

  

public PeriodicTask.Builder setPersisted(boolean isPersisted)

     

可选的setter,用于指定是否应在重新引导后保留此任务。对于定期任务,此默认值为true,调用者必须持有权限android.Manifest.permission.RECEIVE_BOOT_COMPLETED,否则将忽略此setter。

所以,不要担心制作自己的BootBroadcastReceiver,只需添加启动权限。

由于主要问题是关于同时防止多次运行GcmTaskService ...可以通过为任务添加相同的标记来完成。默认情况下,如果任务(通过相同名称)已在运行,则会发生。通过执行setUpdateCurrent(true),在调用schedule()时将更新/替换任务的参数。

来源:PeriodicTask.Builder.setUpdateCurrent(boolean)