【问题标题】:How to observe last emitted WorkManager getWorkInfoByIdLiveData with Android Worker如何使用 Android Worker 观察最后发出的 WorkManager getWorkInfoByIdLiveData
【发布时间】:2020-01-07 15:54:08
【问题描述】:

我当前的 Android 应用程序采用了

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

worker 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)")

    }
}

两个“虚拟”活动用于使作为生命周期所有者的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 {}})

这对于测试 2) 是不正确的。正如我应该看到的“......最后的可用数据自动”。当 WorkerActivity 恢复时

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

【问题讨论】:

  • 您有在任何地方展示此问题的示例项目吗?
  • @Anatolii 不,我不知道,但是我认为这没有必要,因为这是一个如此简单的机制,而且它不像代码 cmets 所描述的那样工作。

标签: android android-livedata android-workmanager


【解决方案1】:

当您在活动之间切换时,您的观察者似乎正在被破坏。我不能 100% 保证这是正在发生的事情,但根据日志,它很有可能至少达到 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

希望这会有所帮助!

【讨论】:

    【解决方案2】:

    你的观察者没有被调用的原因是WorkerActivity生命周期在测试2中没有移动到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.
    

    在obsrever的活动变化过程中你的数据没有变化,WorkInfo一直处于运行状态。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-05-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-12
      • 2020-04-27
      • 2023-03-16
      相关资源
      最近更新 更多