如何使用 Android Worker 观察最后一个发出的 WorkManager getWorkInfoByIdLiveData?

3

我目前的安卓应用程序使用

archWorkerRuntimeVersion = '2.3.0-beta02'

api "androidx.work:work-runtime:$archWorkerRuntimeVersion"
api "androidx.work:work-runtime-ktx:$archWorkerRuntimeVersion"

我通过LiveData观察工作状态,如下所示:

 WorkManager.getInstance(applicationContext).getWorkInfoByIdLiveData(experimentRequest.id).observe(lifeCycleOwner, observer)

其中lifeCycleOwner是我的Activity,observer是一个静态val

private val observer = object : Observer<WorkInfo> {
    override fun onChanged(it: WorkInfo?) {
        Log.e("Worker", "this is our single observer $it $this")
        if (it == null) return
        repository.storeCurrentWorkId(it.id)
    }
}

observe(lifeCycleOwner, observer)的注释说明如下:

/**
 * Adds the given observer to the observers list within the lifespan of the given
 * owner. The events are dispatched on the main thread. If LiveData already has data
 * set, it will be delivered to the observer.
 * <p>
 * The observer will only receive events if the owner is in {@link Lifecycle.State#STARTED}
 * or {@link Lifecycle.State#RESUMED} state (active).
 * <p>
 * If the owner moves to the {@link Lifecycle.State#DESTROYED} state, the observer will
 * automatically be removed.
 * <p>
 * When data changes while the {@code owner} is not active, it will not receive any updates.
 * If it becomes active again, it will receive the last available data automatically.
 * <p>
 * LiveData keeps a strong reference to the observer and the owner as long as the
 * given LifecycleOwner is not destroyed. When it is destroyed, LiveData removes references to
 * the observer &amp; the owner.
 * <p>
 * If the given owner is already in {@link Lifecycle.State#DESTROYED} state, LiveData
 * ignores the call.
 * <p>
 * If the given owner, observer tuple is already in the list, the call is ignored.
 * If the observer is already in the list with another owner, LiveData throws an
 * {@link IllegalArgumentException}.
 *
 * @param owner    The LifecycleOwner which controls the observer
 * @param observer The observer that will receive the events
 */

然而,这个说法似乎并不成立。

If it becomes active again, it will receive the last available data automatically.

除非我误解了它的意思。
我理解为当我的活动重新变为活跃状态时,我将接收到最新(最后)可用的数据。
从我的测试来看,情况并非如此,我只会接收到在我的活动再次变为活跃状态之后发送的任何新数据。
我做错了什么?
有没有办法在我的活动变为活跃时接收到最新的数据?
更新:
我已经创建了以下简单的Android应用程序来展示这个问题。
此Android应用程序由三个活动组成。
Dummy Main Activity
Worker Activity
Dummy Second Activity

我的测试涉及

1). Starting App with Dummy Main Activity, navigating to WorkerActivity, starting Worker and waiting for the worker to SUCCEED

2). Starting App with Dummy Main Activity, navigating to WorkerActivity, starting Worker, then navigate to Dummy Second Activity and returning to WorkerActivity

3). Starting App with Dummy Main Activity, navigating to WorkerActivity, starting Worker, then return to Dummy Main Activity and returning to WorkerActivity

工作器 Activity 开始并观察 LiveData,如下所示:

class WorkerActivity : AppCompatActivity(), Observer<WorkInfo?> {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_ninth)

        findViewById<Button>(R.id.start_work_tags_button).setOnClickListener {
            doSomeWork()
        }

        findViewById<Button>(R.id.start_work_button).setOnClickListener {
            startActivity(Intent(this@WorkerActivity, Seventh::class.java))
        }

    }

    private fun doSomeWork() {
        val ninthRequest: OneTimeWorkRequest = manufactureOneTimeWorkRequest(NinthWorker::class.java)

        WorkManager.getInstance(applicationContext)
            .beginUniqueWork(UNIQUE_WORK_NAME, ExistingWorkPolicy.KEEP, ninthRequest)
            .enqueue()

        val workInfos = WorkManager.getInstance(applicationContext).getWorkInfoByIdLiveData(ninthRequest.id)
        workInfos.observe(this as LifecycleOwner, this as Observer<in WorkInfo>)
    }

    private fun manufactureOneTimeWorkRequest(klazz: Class<out CoroutineWorker>): OneTimeWorkRequest {
        return OneTimeWorkRequest.Builder(klazz).addTag(WORK_IN_PROGRESS_TAG + "${UUID.randomUUID()}").build()
    }

    companion object {
        private const val WORK_IN_PROGRESS_TAG = "SYNC-IN-PROGRESS-TAG"
        private const val UNIQUE_WORK_NAME = "SYNC-UNIQUE_WORK_NAME"
    }

    override fun onChanged(workInfo: WorkInfo?) {
        Log.e("NINTH", "onChanged($workInfo)")

    }
}

两个“Dummy”活动被用来使WorkerActivity成为生命周期所有者并处于“非活动状态”。
我在测试1)中看到的日志如下:
2020-01-14 10:54:36.114 23452-23452/org.vulgaris.behave E/APPLICATION: onActivityCreated() org.vulgaris.behave.sixth.DummyMainActivity@cdc2743
2020-01-14 10:54:36.228 23452-23452/org.vulgaris.behave E/APPLICATION: onActivityStarted() org.vulgaris.behave.sixth.DummyMainActivity@cdc2743
2020-01-14 10:54:36.230 23452-23452/org.vulgaris.behave E/APPLICATION: onActivityResumed() org.vulgaris.behave.sixth.DummyMainActivity@cdc2743
2020-01-14 10:54:43.324 23452-23452/org.vulgaris.behave E/APPLICATION: onActivityPaused() org.vulgaris.behave.sixth.DummyMainActivity@cdc2743
2020-01-14 10:54:43.343 23452-23452/org.vulgaris.behave E/APPLICATION: onActivityCreated() org.vulgaris.behave.ninth.WorkerActivity@abd837d
2020-01-14 10:54:43.386 23452-23452/org.vulgaris.behave E/APPLICATION: onActivityStarted() org.vulgaris.behave.ninth.WorkerActivity@abd837d
2020-01-14 10:54:43.387 23452-23452/org.vulgaris.behave E/APPLICATION: onActivityResumed() org.vulgaris.behave.ninth.WorkerActivity@abd837d
2020-01-14 10:54:43.776 23452-23452/org.vulgaris.behave E/APPLICATION: onActivityStopped() org.vulgaris.behave.sixth.DummyMainActivity@cdc2743
2020-01-14 10:54:43.778 23452-23452/org.vulgaris.behave E/APPLICATION: onActivitySaveInstanceState() org.vulgaris.behave.sixth.DummyMainActivity@cdc2743
2020-01-14 10:54:48.812 23452-23452/org.vulgaris.behave E/WorkerActivity: onChanged(WorkInfo{mId='f3655bdd-3b1d-4e59-a896-3798ec860856', mState=ENQUEUED, mOutputData=Data {}, mTags=[org.vulgaris.behave.worker.NinthWorker, SYNC-IN-PROGRESS-TAG691b47cb-143f-42fc-8d88-903880e1f699], mProgress=Data {}})
2020-01-14 10:54:48.826 23452-23584/org.vulgaris.behave E/NinthWorker:  doWork 56fd9de0-ad8e-4275-b8a0-28e0cd045b9c  inputData = Data {}
2020-01-14 10:54:48.829 23452-23452/org.vulgaris.behave E/WorkerActivity: onChanged(WorkInfo{mId='f3655bdd-3b1d-4e59-a896-3798ec860856', mState=RUNNING, mOutputData=Data {}, mTags=[org.vulgaris.behave.worker.NinthWorker, SYNC-IN-PROGRESS-TAG691b47cb-143f-42fc-8d88-903880e1f699], mProgress=Data {}})
2020-01-14 10:55:48.851 23452-23583/org.vulgaris.behave I/WM-WorkerWrapper: Worker result SUCCESS for Work [ id=f3655bdd-3b1d-4e59-a896-3798ec860856, tags={ org.vulgaris.behave.worker.NinthWorker, SYNC-IN-PROGRESS-TAG691b47cb-143f-42fc-8d88-903880e1f699 } ]
2020-01-14 10:55:48.902 23452-23452/org.vulgaris.behave E/WorkerActivity: onChanged(WorkInfo{mId='f3655bdd-3b1d-4e59-a896-3798ec860856', mState=SUCCEEDED, mOutputData=Data {}, mTags=[org.vulgaris.behave.worker.NinthWorker, SYNC-IN-PROGRESS-TAG691b47cb-143f-42fc-8d88-903880e1f699], mProgress=Data {}})

我看到的测试2)的日志如下所示:

2020-01-14 10:59:20.726 23452-23452/org.vulgaris.behave E/APPLICATION: onActivityCreated() org.vulgaris.behave.sixth.DummyMainActivity@6a03dee
2020-01-14 10:59:20.780 23452-23452/org.vulgaris.behave E/APPLICATION: onActivityStarted() org.vulgaris.behave.sixth.DummyMainActivity@6a03dee
2020-01-14 10:59:20.781 23452-23452/org.vulgaris.behave E/APPLICATION: onActivityResumed() org.vulgaris.behave.sixth.DummyMainActivity@6a03dee
2020-01-14 10:59:23.781 23452-23452/org.vulgaris.behave E/APPLICATION: onActivityPaused() org.vulgaris.behave.sixth.DummyMainActivity@6a03dee
2020-01-14 10:59:23.799 23452-23452/org.vulgaris.behave E/APPLICATION: onActivityCreated() org.vulgaris.behave.ninth.WorkerActivity@2fe5636
2020-01-14 10:59:23.836 23452-23452/org.vulgaris.behave E/APPLICATION: onActivityStarted() org.vulgaris.behave.ninth.WorkerActivity@2fe5636
2020-01-14 10:59:23.837 23452-23452/org.vulgaris.behave E/APPLICATION: onActivityResumed() org.vulgaris.behave.ninth.WorkerActivity@2fe5636
2020-01-14 10:59:24.209 23452-23452/org.vulgaris.behave E/APPLICATION: onActivityStopped() org.vulgaris.behave.sixth.DummyMainActivity@6a03dee
2020-01-14 10:59:24.210 23452-23452/org.vulgaris.behave E/APPLICATION: onActivitySaveInstanceState() org.vulgaris.behave.sixth.DummyMainActivity@6a03dee
2020-01-14 10:59:30.564 23452-23452/org.vulgaris.behave E/WorkerActivity: onChanged(WorkInfo{mId='da800c85-485d-4cb5-9931-d3f20edf611e', mState=ENQUEUED, mOutputData=Data {}, mTags=[SYNC-IN-PROGRESS-TAG6c6ff5e2-b8a7-4f73-99e6-c112f7598287, org.vulgaris.behave.worker.NinthWorker], mProgress=Data {}})
2020-01-14 10:59:30.585 23452-23452/org.vulgaris.behave E/WorkerActivity: onChanged(WorkInfo{mId='da800c85-485d-4cb5-9931-d3f20edf611e', mState=RUNNING, mOutputData=Data {}, mTags=[SYNC-IN-PROGRESS-TAG6c6ff5e2-b8a7-4f73-99e6-c112f7598287, org.vulgaris.behave.worker.NinthWorker], mProgress=Data {}})
2020-01-14 10:59:30.585 23452-23585/org.vulgaris.behave E/NinthWorker:  doWork 6407357d-0471-41ee-8ea2-6cedeaf1e463  inputData = Data {}
2020-01-14 10:59:31.749 23452-23452/org.vulgaris.behave E/APPLICATION: onActivityPaused() org.vulgaris.behave.ninth.WorkerActivity@2fe5636
2020-01-14 10:59:31.767 23452-23452/org.vulgaris.behave E/APPLICATION: onActivityCreated() org.vulgaris.behave.seventh.DummySecondActivity@3572f3a
2020-01-14 10:59:31.834 23452-23452/org.vulgaris.behave E/APPLICATION: onActivityStarted() org.vulgaris.behave.seventh.DummySecondActivity@3572f3a
2020-01-14 10:59:31.835 23452-23452/org.vulgaris.behave E/APPLICATION: onActivityResumed() org.vulgaris.behave.seventh.DummySecondActivity@3572f3a
2020-01-14 10:59:32.211 23452-23452/org.vulgaris.behave E/APPLICATION: onActivityStopped() org.vulgaris.behave.ninth.WorkerActivity@2fe5636
2020-01-14 10:59:32.211 23452-23452/org.vulgaris.behave E/APPLICATION: onActivitySaveInstanceState() org.vulgaris.behave.ninth.WorkerActivity@2fe5636
2020-01-14 10:59:33.112 23452-23452/org.vulgaris.behave E/APPLICATION: onActivityPaused() org.vulgaris.behave.seventh.DummySecondActivity@3572f3a
2020-01-14 10:59:33.128 23452-23452/org.vulgaris.behave E/APPLICATION: onActivityStarted() org.vulgaris.behave.ninth.WorkerActivity@2fe5636
2020-01-14 10:59:33.129 23452-23452/org.vulgaris.behave E/APPLICATION: onActivityResumed() org.vulgaris.behave.ninth.WorkerActivity@2fe5636

I SHOULD SEE "WorkerActivity: onChanged(WorkInfo{mId='da800c85-485d-4cb5-9931-d3f20edf611e', mState=RUNNING, mOutputData=Data {}, mTags=[SYNC-IN-PROGRESS-TAG6c6ff5e2-b8a7-4f73-99e6-c112f7598287, org.vulgaris.behave.worker.NinthWorker], mProgress=Data {}})" HERE

2020-01-14 10:59:33.510 23452-23452/org.vulgaris.behave E/APPLICATION: onActivityStopped() org.vulgaris.behave.seventh.DummySecondActivity@3572f3a
2020-01-14 10:59:33.512 23452-23452/org.vulgaris.behave E/APPLICATION: onActivityDestroyed() org.vulgaris.behave.seventh.DummySecondActivity@3572f3a
2020-01-14 11:00:30.624 23452-23583/org.vulgaris.behave I/WM-WorkerWrapper: Worker result SUCCESS for Work [ id=da800c85-485d-4cb5-9931-d3f20edf611e, tags={ SYNC-IN-PROGRESS-TAG6c6ff5e2-b8a7-4f73-99e6-c112f7598287, org.vulgaris.behave.worker.NinthWorker } ]
2020-01-14 11:00:30.673 23452-23452/org.vulgaris.behave E/WorkerActivity: onChanged(WorkInfo{mId='da800c85-485d-4cb5-9931-d3f20edf611e', mState=SUCCEEDED, mOutputData=Data {}, mTags=[SYNC-IN-PROGRESS-TAG6c6ff5e2-b8a7-4f73-99e6-c112f7598287, org.vulgaris.behave.worker.NinthWorker], mProgress=Data {}})

当 WorkerActivity 被恢复时,我应该看到“...自动显示最后可用的数据。”因此对于测试2)来说这是不正确的。

为什么 LiveData 观察者在 WorkerActivity 恢复时不会自动触发?


1
你有展示这个问题的样例项目吗? - Anatolii
@Anatolii,我没有,但我认为这并不必要,因为这是一个非常简单的机制,而且它并不像代码注释所描述的那样工作。 - Hector
2个回答

0
您的观察者不被调用的原因是,在“测试2)”中,WorkerActivity生命周期没有移动到Lifecycle.State.DESTROYED状态(只是因为如果它确实移动到Lifecycle.State.DESTROYED,那么观察者将被删除,并且在工作完成后不能使用mState=SUCCEEDED进行调用)。因此,观察者没有被删除,它在工作完成之前一直持续观察LiveData
因此,与文档没有任何矛盾。
 * When data changes while the {@code owner} is not active, it will not receive any updates.
 * If it becomes active again, it will receive the last available data automatically.

在观察者活动变化期间,您的数据并未发生更改,WorkInfo 一直处于运行状态。


0

看起来当你在不同的活动之间切换时,你的观察者被销毁了。我不能百分之百地保证这就是发生的事情,但根据日志记录,有很大的可能性它至少会达到Lifecycle.DESTROYED状态。

在你为hasActiveObservers()设置观察者之前,你可以在onClick中使用一个检查。


观察者与生命周期的状态相关联。

LiveData 认为 Observer 类代表的观察者处于 STARTEDRESUMED 状态时,处于活动状态。

这意味着如果您的活动处于这两种状态之一,您将收到更新。如果我们查看每种状态的条件:

RESUMED

  • 此状态在 onResume 调用后达成。

STARTED

  • 对于 Activity,此状态有两种情况:
  • 在 onStart 调用后;
  • 就在 onPause 调用之前。

根据这个,实际上您应该看到您的观察者在 onStart() 后立即被调用。

然而,文档也列出了

如果所有者移动到{@link Lifecycle.State#DESTROYED}状态,观察员将自动被删除。
这意味着您的观察员将不再接收任何更新。 DESTROYED 此状态在Activity的onDestroy调用之前达到。
现在您的日志并未显示onActivityDestroyed,但似乎至少可以根据以下内容进入Lifecycle.STATE == DESTROYED。
2020-01-14 10:59:32.211 23452-23452/org.vulgaris.behave E/APPLICATION: onActivityStopped() org.vulgaris.behave.ninth.WorkerActivity@2fe5636

并且

2020-01-14 10:59:32.211 23452-23452/org.vulgaris.behave E/APPLICATION: onActivitySaveInstanceState() org.vulgaris.behave.ninth.WorkerActivity@2fe5636

希望这能有所帮助!

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