Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/file/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么Android Worker成功完成并调用onStopped()_Android_Androidx_Android Workmanager - Fatal编程技术网

为什么Android Worker成功完成并调用onStopped()

为什么Android Worker成功完成并调用onStopped(),android,androidx,android-workmanager,Android,Androidx,Android Workmanager,我当前的安卓应用程序使用了androidx。工作:工作运行时:2.2.0-rc01 我的工作代码类似于:- class SyncWorker(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) { private var syncWorkerResult: Result = Result.success() override fun doWork(): Result

我当前的安卓应用程序使用了androidx。工作:工作运行时:2.2.0-rc01

我的工作代码类似于:-

class SyncWorker(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) {

    private var syncWorkerResult: Result = Result.success()

    override fun doWork(): Result {

        return syncWorkerResult
    }

    override fun onStopped() {
        Log.i(TAG, "onStopped() $isStopped")

        super.onStopped()

    }
}
就我所了解的工人文档而言,我不应该看到以下日志:-

2019-08-21 14:25:55.183 22716-22750/com.my.app I/WM-WorkerWrapper: Worker result SUCCESS for Work [ id=70a5ff81-1b4b-4604-9d2e-a0b3d342a608, tags={ com.my.app.sync.SyncWorker, SYNC-IN-PROGRESS-TAG } ]
2019-08-21 14:25:55.202 22716-22768/com.my.app I/SyncWorker: onStopped() true
我做错了什么

由于我的员工正在报告结果成功,成功的定义如下:-

Returns an instance of ListenableWorker.Result that can be used to indicate that the work completed successfully. Any work that depends on this can be executed as long as all of its other dependencies and constraints are met.
这显然是工作程序代码中的一个缺陷,因为上面的日志显示我的工作程序已成功完成,然后被停止,如果已经成功完成,有什么可以“停止”的

我不明白为什么要为成功完成的工作程序调用
androidx.work.impl.workerRapper
interrupt方法

/**
 * @hide
 */
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public void interrupt(boolean cancelled) {
    mInterrupted = true;
    // Resolve WorkerWrapper's future so we do the right thing and setup a reschedule
    // if necessary. mInterrupted is always true here, we don't really care about the return
    // value.
    tryCheckForInterruptionAndResolve();
    if (mInnerFuture != null) {
        // Propagate the cancellations to the inner future.
        mInnerFuture.cancel(true);
    }
    // Worker can be null if run() hasn't been called yet.
    if (mWorker != null) {
        mWorker.stop();
    }
}

通过搜索Android worker源代码,我发现了这种方法

/**
 * Stops a unit of work.
 *
 * @param id The work id to stop
 * @return {@code true} if the work was stopped successfully
 */
public boolean stopWork(String id) {
    synchronized (mLock) {
        Logger.get().debug(TAG, String.format("Processor stopping %s", id));
        WorkerWrapper wrapper = mEnqueuedWorkMap.remove(id);
        if (wrapper != null) {
            wrapper.interrupt(false);
            Logger.get().debug(TAG, String.format("WorkerWrapper stopped for %s", id));
            return true;
        }
        Logger.get().debug(TAG, String.format("WorkerWrapper could not be found for %s", id));
        return false;
    }
}
调用
wrapper.interrupt(false)mEnqueuedWorkMap
中存在的工作者ID时,使用code>方法,如此调试变量图像所示

下面是WorkManager在我的Worker调用onStopped()方法时的日志

2019-08-23 13:02:32.754 21031-21031/com.my.app D/WM-PackageManagerHelper: androidx.work.impl.background.systemjob.SystemJobService enabled
2019-08-23 13:02:32.754 21031-21031/com.my.app D/WM-Schedulers: Created SystemJobScheduler and enabled SystemJobService
2019-08-23 13:02:32.763 21031-21085/com.my.app D/WM-ForceStopRunnable: Performing cleanup operations.
2019-08-23 13:02:32.884 21031-21085/com.my.app D/WM-ForceStopRunnable: Application was force-stopped, rescheduling.
2019-08-23 13:02:44.219 21031-21098/com.my.app D/WM-PackageManagerHelper: androidx.work.impl.background.systemalarm.RescheduleReceiver enabled
2019-08-23 13:02:44.237 21031-21098/com.my.app D/WM-SystemJobScheduler: Scheduling work ID e6a31ec8-a155-4d15-8cf7-af505c70e323 Job ID 0
2019-08-23 13:02:44.244 21031-21098/com.my.app D/WM-GreedyScheduler: Starting work for e6a31ec8-a155-4d15-8cf7-af505c70e323
2019-08-23 13:02:44.268 21031-21085/com.my.app D/WM-PackageManagerHelper: androidx.work.impl.background.systemalarm.RescheduleReceiver enabled
2019-08-23 13:02:44.302 21031-21085/com.my.app D/WM-SystemJobScheduler: Scheduling work ID 075fb9b3-e19b-463b-89f1-9e737e476d5b Job ID 1
2019-08-23 13:02:44.331 21031-21101/com.my.app D/WM-Processor: Processor: processing e6a31ec8-a155-4d15-8cf7-af505c70e323
2019-08-23 13:02:44.723 21031-21031/com.my.app D/WM-WorkerWrapper: Starting work for com.my.app.sync.SyncWorker
2019-08-23 13:02:44.730 21031-21031/com.my.app D/WM-SystemJobService: onStartJob for e6a31ec8-a155-4d15-8cf7-af505c70e323
2019-08-23 13:02:44.731 21031-21101/com.my.app D/WM-Processor: Work e6a31ec8-a155-4d15-8cf7-af505c70e323 is already enqueued for processing
2019-08-23 13:02:44.795 21031-21098/com.my.app D/WM-WorkerWrapper: com.my.app.sync.SyncWorker returned a Success {mOutputData=androidx.work.Data@0} result.
2019-08-23 13:02:44.797 21031-21098/com.my.app I/WM-WorkerWrapper: Worker result SUCCESS for Work [ id=e6a31ec8-a155-4d15-8cf7-af505c70e323, tags={ com.my.app.sync.SyncWorker, SYNC-IN-PROGRESS-TAG } ]
2019-08-23 13:02:44.808 21031-21031/com.my.app D/WM-Processor: Processor e6a31ec8-a155-4d15-8cf7-af505c70e323 executed; reschedule = false
2019-08-23 13:02:44.808 21031-21031/com.my.app D/WM-SystemJobService: e6a31ec8-a155-4d15-8cf7-af505c70e323 executed on JobScheduler
2019-08-23 13:02:44.814 21031-21098/com.my.app D/WM-GreedyScheduler: Cancelling work ID e6a31ec8-a155-4d15-8cf7-af505c70e323
2019-08-23 13:02:44.828 21031-21085/com.my.app D/WM-Processor: Processor stopping e6a31ec8-a155-4d15-8cf7-af505c70e323
2019-08-23 13:02:44.829 21031-21085/com.my.app D/WM-Processor: WorkerWrapper could not be found for e6a31ec8-a155-4d15-8cf7-af505c70e323
2019-08-23 13:02:44.829 21031-21085/com.my.app D/WM-StopWorkRunnable: StopWorkRunnable for e6a31ec8-a155-4d15-8cf7-af505c70e323; Processor.stopWork = false
2019-08-23 13:02:44.856 21031-21098/com.my.app D/WM-PackageManagerHelper: androidx.work.impl.background.systemalarm.RescheduleReceiver enabled
2019-08-23 13:02:44.874 21031-21098/com.my.app D/WM-SystemJobScheduler: Scheduling work ID ba72423c-5e4b-425c-aaab-a9a14efaf3f8 Job ID 2
2019-08-23 13:02:44.880 21031-21098/com.my.app D/WM-GreedyScheduler: Starting work for ba72423c-5e4b-425c-aaab-a9a14efaf3f8
2019-08-23 13:02:44.882 21031-21101/com.my.app D/WM-Processor: Processor: processing ba72423c-5e4b-425c-aaab-a9a14efaf3f8
2019-08-23 13:02:44.897 21031-21031/com.my.app D/WM-SystemJobService: onStartJob for ba72423c-5e4b-425c-aaab-a9a14efaf3f8
2019-08-23 13:02:44.900 21031-21031/com.my.app D/WM-WorkerWrapper: Starting work for com.my.app.sync.SyncWorker
2019-08-23 13:02:44.908 21031-21101/com.my.app D/WM-Processor: Work ba72423c-5e4b-425c-aaab-a9a14efaf3f8 is already enqueued for processing
2019-08-23 13:02:44.973 21031-21101/com.my.app D/WM-WorkerWrapper: com.my.app.sync.SyncWorker returned a Success {mOutputData=androidx.work.Data@0} result.
2019-08-23 13:02:44.975 21031-21101/com.my.app I/WM-WorkerWrapper: Worker result SUCCESS for Work [ id=ba72423c-5e4b-425c-aaab-a9a14efaf3f8, tags={ com.my.app.sync.SyncWorker, SYNC-IN-PROGRESS-TAG } ]
2019-08-23 13:02:44.989 21031-21101/com.my.app D/WM-GreedyScheduler: Cancelling work ID ba72423c-5e4b-425c-aaab-a9a14efaf3f8
2019-08-23 13:02:44.996 21031-21085/com.my.app D/WM-Processor: Processor stopping ba72423c-5e4b-425c-aaab-a9a14efaf3f8
2019-08-23 13:02:44.997 21031-21085/com.my.app D/WM-WorkerWrapper: Work interrupted for Work [ id=ba72423c-5e4b-425c-aaab-a9a14efaf3f8, tags={ com.my.app.sync.SyncWorker, SYNC-IN-PROGRESS-TAG } ]

2019-08-23 13:02:44.999 21031-21085/com.my.app I/SyncWorker: onStopped() ba72423c-5e4b-425c-aaab-a9a14efaf3f8 Success {mOutputData=androidx.work.Data@0}

2019-08-23 13:02:44.999 21031-21085/com.my.app D/WM-Processor: WorkerWrapper stopped for ba72423c-5e4b-425c-aaab-a9a14efaf3f8
2019-08-23 13:02:44.999 21031-21085/com.my.app D/WM-StopWorkRunnable: StopWorkRunnable for ba72423c-5e4b-425c-aaab-a9a14efaf3f8; Processor.stopWork = true
2019-08-23 13:02:45.045 21031-21031/com.my.app D/WM-Processor: Processor ba72423c-5e4b-425c-aaab-a9a14efaf3f8 executed; reschedule = false
2019-08-23 13:02:45.046 21031-21031/com.my.app D/WM-SystemJobService: ba72423c-5e4b-425c-aaab-a9a14efaf3f8 executed on JobScheduler
2019-08-23 13:02:45.047 21031-21031/com.my.app D/WM-SystemJobService: onStopJob for ba72423c-5e4b-425c-aaab-a9a14efaf3f8
2019-08-23 13:02:45.049 21031-21098/com.my.app D/WM-Processor: Processor stopping ba72423c-5e4b-425c-aaab-a9a14efaf3f8
2019-08-23 13:02:45.049 21031-21098/com.my.app D/WM-Processor: WorkerWrapper could not be found for ba72423c-5e4b-425c-aaab-a9a14efaf3f8
2019-08-23 13:02:45.049 21031-21098/com.my.app D/WM-StopWorkRunnable: StopWorkRunnable for ba72423c-5e4b-425c-aaab-a9a14efaf3f8; Processor.stopWork = false
更新

当我在第一个实例完成OK后立即启动worker的第二个实例时,就会发生此问题。第二个实例的行为如上图所示。当我在
doWork()
方法中添加
Thread.sleep(Xms)
时,我可以“控制”何时发生,因为通过增加Xms,问题需要很长时间才能出现

e、 g.如果我设置了一个“循环”,每次前一个worker完成OK时启动一个新的worker,我总是会看到这个问题,即后续的worker实例将完成
SUCCESS
并调用
onStopped()

更新二

下面是一段代码片段,显示如何启动Worker

val refreshDatabaseWork: OneTimeWorkRequest = OneTimeWorkRequest.Builder(SyncWorker::class.java)
        .keepResultsForAtLeast(1L, TimeUnit.NANOSECONDS)
        .addTag(WORK_IN_PROGRESS_TAG).build()
WorkManager.getInstance(application).beginUniqueWork(UNIQUE_WORK_NAME, ExistingWorkPolicy.KEEP, refreshDatabaseWork).enqueue()

我打开了一个小项目的问题,该项目复制了问题,按照“工人”类的文档所述,它的工作符合预期:

一旦你从这里回来 *方法,则工人被视为已完成其工作,并将被销毁。如果 *您需要在自己选择的线程上异步执行工作

也适用于ListenableWorker类的onStopped()方法

 /**
     * This method is invoked when this Worker has been told to stop.  This could happen due
     * to an explicit cancellation signal by the user, or because the system has decided to preempt
     * the task.  In these cases, the results of the work will be ignored by WorkManager.  All
     * processing in this method should be lightweight - there are no contractual guarantees about
     * which thread will invoke this call, so this should not be a long-running or blocking
     * operation.
     */

我创建了一个简单的示例:单击按钮时,它只会启动提供给您的
SyncWorker
。没有连续的工人被启动,只有一个工人,我甚至简化了工人的创建:

val refreshDatabaseWork: OneTimeWorkRequest = OneTimeWorkRequest.Builder(SyncWorker::class.java)
    .build()

WorkManager
    .getInstance(application)
    .enqueue(refreshDatabaseWork)
当我按下按钮时,有时调用
onStopped()
,有时不调用。它很少被调用,大约每20次点击一次。这种不一致的行为看起来确实像一个bug。在
处理器
实现中有一个
onExecuted()
回调方法,每次工作进程完成时都会调用该方法:

@覆盖
已执行的公共无效(
@非空的最终字符串workSpecId,
布尔需求计划
) {
已同步(mLock){
mEnqueuedWorkMap.remove(工作规范ID);
Logger.get().debug(标记,字符串.format(“%s%s已执行;重新调度=%s”),
getClass().getSimpleName(),workSpecId,needsReschedule));
for(ExecutionListener ExecutionListener:mOuterListeners){
executionListener.onExecuted(工作规范ID、需求计划);
}
}
}
此方法从
mEnqueuedWorkMap
中删除工作程序包装,但有时
stopWork()
方法会在删除包装之前获取该包装,从而停止工作程序并调用
onStopped()
回调

我还注意到,
wrapper.interrupt(false)
call接收
cancelled
boolean标志,在我们的例子中它是false,但是这个标志从未被方法使用过,它看起来也很奇怪


我还尝试了androidx.work:work runtime:2.2.0
,它现在可用,但结果是一样的。我认为最好创建一个谷歌问题,从图书馆开发者那里得到答案。这个行为看起来很奇怪,但我只能猜测它的意图。

这个错误已经在及更高版本中修复。 因此,我更改了依赖项,无法再复制它:

implementation "androidx.work:work-runtime:2.3.0-alpha03"

从我对onStopped方法的理解来看,这不是设计的工作方式。调用onStopped()时,辅助结果将始终被取消。在我的例子中,您可以看到工作已成功完成,然后调用onStopped。如果工作人员已经成功完成,有什么可以“停止”的?我的工人没有执行任何工作,只是成功地完成了。我相信这是一个错误,当工作人员“非常/太快”完成时会发生@Hector为什么要在返回
Result.success()时取消它?只是不要
覆盖乐趣,继续前进。@MartinZeitler它不会被取消,正如日志和我获得成功结果的事实所示。我相信worker代码中存在一个bug,它允许一些worker实例成功完成,但仍然调用onStopped()。我必须重写onStopped(),因为当工作人员正在执行且用户注销时,我需要清除我的应用程序数据库。我创建了一个简单的示例,使用相同的
工作运行时
版本,但工作人员在完成后不会被取消,并且不会调用
onStop()
。你能为这个问题添加更多的细节吗,你测试的是哪个Android版本?工人请求是否有任何约束?运行worker时,应用程序是否在后台?你如何测试工人?我在日志中看到,该应用程序在执行工作程序前几秒钟强制停止。在您的简单示例中,每次上一个实例完成后,尝试启动后续工作程序。好的,我保证您会看到我的问题。您是指
workManager.beginWith(firstWork)。然后(secondWork)
序列吗?我对它进行了很多测试,确实调用了
onStop()
,但只有几次,当我