Android 的“OneTimeWorker”问题,它在应用程序启动时执行

问题描述 投票:0回答:1

简短描述:


我目前在 Android Studio 中与

OneTimeWorkRequest()
一起工作。我想要实现的是创建一个后台工作者,它在特定时间运行并重复“几乎”,比如每小时(09:00、10:00 等)。它不一定是准确的,但在长时间运行后不应变化太大。

我已经知道,由于 android 的限制(比如省电机制等),worker 至少每 15 分钟运行一次。我不需要工作人员在给定时间准确运行,但至少几乎在目标时间附近运行!这就是为什么我使用

OneTimeWorkRequest()
而不是
PeriodicWorkRequest()
的原因,因为我需要在为工作人员设置间隔时有变化的可能性,因为文档提到
PeriodicWorkRequest()
会增加从一次执行到另一次执行的时间延迟。

我做了什么:


我创建了一个自定义 Worker-Class 并在我的

OneTimeWorkRequest()
中使用了
MainActivity
来创建 BackgroundWorker。我已将工人的
setInitialDelay()
设置为20分钟以进行测试。每当 worker 执行
doWork()
时,它都会在执行结束时创建另一个
OneTimeWorkRequest()
,以便在给定时间创建一个 worker 链。工作人员使用
enqueueUniqueWork()
中的
WorkerManager.getInstance(context)
方法排队,并计算间隔。

问题:


每次关闭App的进程再打开App,Worker直接执行。此外,当我列出由指定标签创建的所有工人时,它会列出许多工人。在我看来,我的逻辑在没有关闭旧工人的情况下创造了太多工人,还是创造了多个工人?然而我认为

enqueueUniqueWork()
只会替换或创建具有给定标签的唯一/单个工人......此外,
WorkManager.getInstance(this).cancelAllWorkByTag(TAG)
功能不会关闭(在本文后面)列出的工人!

现在对我来说,如何在给定时间创建工作人员执行并不重要,但如果可能的话,如何使用

OneTimeWorkRequest()
创建一致的工作链,不会造成“工作人员过载”。然而,我对替代解决方案持开放态度。

再说一遍:

  • 为什么worker在关闭进程打开App后执行?
  • 为什么列出这么多工人?
  • 我的逻辑是创建一个单一的工作链还是多个?
  • 这样我的逻辑是否一致/可用?
  • 为什么工人不使用
    .cancelAllWorkByTag(TAG)
    关闭?

代码:


// MainActivity.java:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    
    ...
    
        // For testing purpose used...
    ListScheduledWorker(TAG);
    WorkManager.getInstance(this).cancelAllWorkByTag(TAG);
    ListScheduledWorker(TAG);
        // ...until here.

    CreateOneTimeWorker();
    
    ...
}

private void CreateOneTimeWorker(){
    long timeValue = 20;
    TimeUnit timeUnit = TimeUnit.MINUTES;
    String workerTag = MhdExpirationPushNotification.class.getSimpleName();
    OneTimeWorkRequest worker = new OneTimeWorkRequest.Builder(CustomPeriodicallyWorker.class)
            .setInitialDelay(timeValue, timeUnit)
            .addTag(workerTag)
            .setConstraints(Constraints.NONE)
            .build();
    WorkManager.getInstance(this).enqueueUniqueWork(workerTag, ExistingWorkPolicy.KEEP, worker);
}

// CustomPeriodicallyWorker.java:

public Result doWork(){
    Log.v(TAG, "Work is in progress");
    try {
        CustomDateFormatter currentDateTime = new CustomDateFormatter();
        CustomDateFormatter targetDateTime = new CustomDateFormatter();
        targetDateTime.AddMinutes(20);
        long timeDifference = targetDateTime.GetDateTime().getTime() - currentDateTime.GetDateTime().getTime();

        OneTimeWorkRequest worker = new OneTimeWorkRequest.Builder(CustomPeriodicallyWorker.class)
                .setInitialDelay(timeDifference, TimeUnit.MILLISECONDS)
                .addTag(TAG)
                .build();
        WorkManager.getInstance(context).enqueueUniqueWork(TAG, ExistingWorkPolicy.REPLACE, worker);

    } catch (Exception e) {
        e.printStackTrace();
    }
    Log.v(TAG, "Work finished");;

    return Result.success();
}

//

MainActivity.java
中的函数,列出所有调度的worker:

private boolean ListScheduledWorker(String tag) {
    WorkManager instance = WorkManager.getInstance(this);
    ListenableFuture<List<WorkInfo>> statuses = instance.getWorkInfosByTag(tag);
    try {
        boolean running = false;
        List<WorkInfo> workInfoList = statuses.get();
        for (WorkInfo workInfo : workInfoList) {
            Log.i(TAG, "Scheduled Worker running with ID: " + workInfo.getId());
            WorkInfo.State state = workInfo.getState();
            running = state == WorkInfo.State.RUNNING | state == WorkInfo.State.ENQUEUED;
        }
        return running;
    } catch (ExecutionException e) {
        e.printStackTrace();
        return false;
    } catch (InterruptedException e) {
        e.printStackTrace();
        return false;
    }
}

//

ListScheduledWorker(String tag)
打印出来:

I/TAG: Scheduled Worker running with ID: 27bb31ed-5984-434f-a6ca-08b50462b3df
    Scheduled Worker running with ID: 2d6abbb1-3a55-4652-83ca-60617631e0ab
    Scheduled Worker running with ID: 3e89851d-7e0b-410d-86b8-e664a4d710f0
    Scheduled Worker running with ID: 430e77b2-5fb8-4596-acd5-51e35a6a538b
    Scheduled Worker running with ID: 73b57443-8195-4c55-a24d-bd643b88e13c
    Scheduled Worker running with ID: 74c8a44b-2a9a-4448-b3d5-e2c085be3d06
    Scheduled Worker running with ID: 75deabd3-08e8-403a-b9d7-6c23f114a908
    Scheduled Worker running with ID: 89ec6239-e215-4ea1-a7bc-fcaa8b63065c
    Scheduled Worker running with ID: 9363038e-be74-4a83-9d1f-eeeda35ebbfa
    Scheduled Worker running with ID: 9a09806f-f0cf-43c1-a4f6-1f10448904f4
    Scheduled Worker running with ID: c6686c56-fd8a-4866-8eb1-5124654b6cb7
    Scheduled Worker running with ID: d3343328-db8f-4c8d-8055-a1acfc9d1c5c
    Scheduled Worker running with ID: dea9272f-6770-45f0-ba66-2c845e156d7b
    Scheduled Worker running with ID: eb4c111c-97c5-46c3-ba5c-ceefe652398c
    Scheduled Worker running with ID: fc71f8dc-1785-43cd-9a44-1fe4e913ca6e
    Scheduled Worker running with ID: fca1bcea-97d9-4066-8b5a-8b5496ffed1e

..每次当我在 Android Studio 或我的物理设备上重建/重启应用程序时,列表都会增长。

java android worker
1个回答
0
投票

我会尽力回答其中一些问题。

为什么worker在关闭进程打开后执行 应用程序?

不确定,但您可以在应用程序启动时取消所有带有该标签的独特工作,这将阻止它自动执行。

为什么列出这么多工人?

WorkManager
WorkInfo
s 保存在它的内部数据库中,并在它认为最好的时候自动清理它。 您可以使用
workmanager.pruneWork()
自己进行清洁,但请按照文档中的说明谨慎使用。

我的逻辑是创建一个单一的工作链还是多个?

它创建单链,因为你正在使用

uniqeWork
ExistingWorkPolicy.REPLACE
.

这样我的逻辑是否一致/可用?

我看不出有什么理由不应该,您创建了自己的周期性工作者实现,可以在不到 15 分钟的时间内执行。

为什么工人不使用 .cancelAllWorkByTag(TAG) 关闭?

如果它没有取消,很可能是您的代码。如文档中所述,取消是尽力而为,因此您需要检查它。 我会单独引用answer

总而言之,如果你有一个尚未开始的待定工人, worker 将被取消并且不会运行。但是,如果工人是 已经在运行,取消工作不会终止 worker 硬时尚 - 它只是将工人的州旗设置为 已取消,如文档中所述。由您来处理 在你的 doWork 中取消并终止工作人员。

一种方法是在你的 doWork 方法中进行一些检查以 通过调用 isStopped() 检查 worker 是否被取消。如果 isStopped 为真,从方法返回结果而不是 继续其余的工作。

还要仔细检查是否使用了相同的标签。由于您使用的是

uniqueWork
,因此您也可以使用
cancelUniqueWork
.

© www.soinside.com 2019 - 2024. All rights reserved.