我已经关注this文章,该文章关于如何在WorkManagers上进行DI,所以我有这个工厂:

 class MyWorkerFactory @Inject constructor(
        val workerFactories: Map<Class<out ListenableWorker>, @JvmSuppressWildcards Provider<ChildWorkerFactory>>
) : WorkerFactory() {

    override fun createWorker(
            appContext: Context,
            workerClassName: String,
            workerParameters: WorkerParameters
    ): ListenableWorker? {

        val foundEntry = workerFactories.entries.find { Class.forName(workerClassName).isAssignableFrom(it.key) }

        return if (foundEntry != null) {
            val factoryProvider = foundEntry.value
            factoryProvider.get().create(appContext, workerParameters)
        } else {
            val workerClass = Class.forName(workerClassName).asSubclass(ListenableWorker::class.java)
            val constructor = workerClass.getDeclaredConstructor(Context::class.java, WorkerParameters::class.java)
            constructor.newInstance(appContext, workerParameters)
        }

    }
}


这是我的模块:

@Retention(AnnotationRetention.RUNTIME)
@MapKey
annotation class WorkerKey(val value: KClass<out ListenableWorker>)


@Module
abstract class ParcelPollModule {

    @Binds
    @IntoMap
    @WorkerKey(ParcelPollWorker::class)
    internal abstract fun bindMyWorkerFactory(worker: ParcelPollWorker.Factory): ChildWorkerFactory


}


这是我的应用程序组件的一部分。然后在我的Application类上执行以下操作:

@Inject lateinit var myWorkerFactory: MyWorkerFactory

private fun setupWorkerFactory() {
        WorkManager.initialize(
                this,
                Configuration.Builder()
                        .setWorkerFactory(myWorkerFactory)
                        .build()
        )
    }


我的工人班:

class ParcelPollWorker constructor(val parcelRepository: LocalParcelRepository,
                                   val correosRepository: CorreosRepository,
                                   appContext: Context, workerParams: WorkerParameters) : RxWorker(appContext, workerParams) {
    override fun createWork(): Single<Result> {
        Timber.w("Parcel poll worker $this here trying to do some work!")
        return parcelRepository.getParcels()
                .flatMapIterable {
                    it
                }

                .map {
                    Timber.d("Parcel poll checking parcel with code ${it.code}")
//                    correosRepository.getParcelStatus(it.code)
                }
                .toList()
                .map { Result.success() }
                .onErrorReturn {
                    Result.failure()
                }

    }


    class Factory @Inject constructor(
            val myRepository: LocalParcelRepository,
            val networkService: CorreosRepository
    ) : ChildWorkerFactory {

        override fun create(appContext: Context, params: WorkerParameters): ListenableWorker {
            return ParcelPollWorker(myRepository, networkService, appContext, params)
        }
    }


}


现在,即使我根本不调度此工作程序,我的日志也会多次打印具有不同实例的Parcel poll worker $this here trying to do some work!(有时为3,有时为6)!此外,在启动应用程序时,实际工作的行会多次打印:

2020-01-08 08:37:40.892 7011-7011/com.myapp.android W/ParcelPollWorker: Parcel poll worker com.myapp.service.worker.ParcelPollWorker@c1f5d23 here trying to do some work!
2020-01-08 08:37:40.923 7011-7011/com.myapp.android W/ParcelPollWorker: Parcel poll worker com.myapp.service.worker.ParcelPollWorker@c80a87f here trying to do some work!
2020-01-08 08:37:40.924 7011-7011/com.myapp.android W/ParcelPollWorker: Parcel poll worker com.myapp.service.worker.ParcelPollWorker@85b9895 here trying to do some work!
2020-01-08 08:37:40.945 7011-7113/com.myapp.android D/ParcelPollWorker$createWork: Parcel poll checking parcel with code 63583511008898301184149
2020-01-08 08:37:40.946 7011-7113/com.myapp.android D/ParcelPollWorker$createWork: Parcel poll checking parcel with code 800692129
2020-01-08 08:37:40.946 7011-7113/com.myapp.android D/ParcelPollWorker$createWork: Parcel poll checking parcel with code PQ5HG70200028570115706M
2020-01-08 08:37:40.946 7011-7113/com.myapp.android D/ParcelPollWorker$createWork: Parcel poll checking parcel with code UX6CFH0459568380108027M
2020-01-08 08:37:40.947 7011-7113/com.myapp.android D/ParcelPollWorker$createWork: Parcel poll checking parcel with code 6307253297994985
2020-01-08 08:37:40.949 7011-7113/com.myapp.android D/ParcelPollWorker$createWork: Parcel poll checking parcel with code 63583560022440001250051
2020-01-08 08:37:40.954 7011-7102/com.myapp.android D/ParcelPollWorker$createWork: Parcel poll checking parcel with code 63583511008898301184149
2020-01-08 08:37:40.955 7011-7102/com.myapp.android D/ParcelPollWorker$createWork: Parcel poll checking parcel with code 800692129
2020-01-08 08:37:40.955 7011-7102/com.myapp.android D/ParcelPollWorker$createWork: Parcel poll checking parcel with code PQ5HG70200028570115706M
2020-01-08 08:37:40.955 7011-7101/com.myapp.android D/ParcelPollWorker$createWork: Parcel poll checking parcel with code 63583511008898301184149
2020-01-08 08:37:40.955 7011-7101/com.myapp.android D/ParcelPollWorker$createWork: Parcel poll checking parcel with code 800692129
2020-01-08 08:37:40.955 7011-7102/com.myapp.android D/ParcelPollWorker$createWork: Parcel poll checking parcel with code UX6CFH0459568380108027M
2020-01-08 08:37:40.955 7011-7101/com.myapp.android D/ParcelPollWorker$createWork: Parcel poll checking parcel with code PQ5HG70200028570115706M
2020-01-08 08:37:40.956 7011-7101/com.myapp.android D/ParcelPollWorker$createWork: Parcel poll checking parcel with code UX6CFH0459568380108027M
2020-01-08 08:37:40.956 7011-7102/com.myapp.android D/ParcelPollWorker$createWork: Parcel poll checking parcel with code 6307253297994985
2020-01-08 08:37:40.956 7011-7102/com.myapp.android D/ParcelPollWorker$createWork: Parcel poll checking parcel with code 63583560022440001250051
2020-01-08 08:37:40.956 7011-7101/com.myapp.android D/ParcelPollWorker$createWork: Parcel poll checking parcel with code 6307253297994985
2020-01-08 08:37:40.956 7011-7101/com.myapp.android D/ParcelPollWorker$createWork: Parcel poll checking parcel with code 63583560022440001250051


这怎么可能?我检查了RxWorker的实现,并且它至少应该打印工作本身,直到工作开始(即有人订阅了它)

public RxWorker(@NonNull Context appContext, @NonNull WorkerParameters workerParams) {
    super(appContext, workerParams);
}

@NonNull
@Override
public ListenableFuture<Result> startWork() {
    mSingleFutureObserverAdapter = new SingleFutureAdapter<>();

    final Scheduler scheduler = getBackgroundScheduler();
    createWork()
            .subscribeOn(scheduler)
            // observe on WM's private thread
            .observeOn(Schedulers.from(getTaskExecutor().getBackgroundExecutor()))
            .subscribe(mSingleFutureObserverAdapter);
    return mSingleFutureObserverAdapter.mFuture;
}


我在这里迷失了可能发生的事情。代码是开源的,可以检查here

上班族的工人:

class ParcelListActivity : BaseActivity() {


    @Inject
    lateinit var myWorkerFactory: MyWorkerFactory


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContentView(R.layout.activity_main)

        setSupportActionBar(toolbar)
        supportActionBar?.setDisplayShowTitleEnabled(true)

        fab.setOnClickListener {
            startActivityForResult(CreateActivity.newIntent(this),
                    REQ_CREATE_PARCEL)
        }

        val constraints = Constraints.Builder()
                .setRequiredNetworkType(NetworkType.CONNECTED)
                .build()


        val uploadWorker = PeriodicWorkRequest.Builder(
                ParcelPollWorker::class.java, 15, TimeUnit.MINUTES)
                .setConstraints(constraints)
                .build()
        WorkManager.getInstance(this).enqueue(uploadWorker)
    }

...

}


@art建议后的更改:

private fun initWorker() {
        val constraints = Constraints.Builder()
                .setRequiredNetworkType(NetworkType.CONNECTED)
                .build()


        val uploadWorker = PeriodicWorkRequest.Builder(
                ParcelPollWorker::class.java, 15, TimeUnit.MINUTES)
                .setConstraints(constraints)
                .build()
        WorkManager.getInstance(this).cancelAllWork()
        WorkManager.getInstance(this).enqueueUniquePeriodicWork(PARCEL_CHECKER_WORKREQUEST, ExistingPeriodicWorkPolicy.REPLACE, uploadWorker)

    }

最佳答案

1.请注意,根据RxWorker的源代码:

@NonNull
@Override
public ListenableFuture<Result> startWork() {
    mSingleFutureObserverAdapter = new SingleFutureAdapter<>();

    final Scheduler scheduler = getBackgroundScheduler();
    createWork()
        .subscribeOn(scheduler)
        // observe on WM's private thread
        .observeOn(Schedulers.from(getTaskExecutor().getBackgroundExecutor()))
        .subscribe(mSingleFutureObserverAdapter);
    return mSingleFutureObserverAdapter.mFuture;
}


工作的执行从调用subscribe对象的Single方法的那一刻开始。所以你的说法是不正确的:


这怎么可能?我检查了RxWorker的实现,并且它至少应该在工作开始之前就打印工作本身(即有人订阅了它)


2.大概在开发过程中的某个时候,您使工作人员使用ParcelListActivity.onCreate方法使代码排队,并且您多次打开了此活动,因此使定期工作人员排队了几次,WorkManager将该工作持久化到其内部数据库中,现在工作是根据您的优先请求配置启动。

要解决此问题,您可以使用cancelAllWork方法。但正如文档声称您使用此方法时,应格外小心!通常,定期工作需要更精确的处理。例如,您可以为工作请求assign a tag,然后可以使用cancelAllWorkByTag方法取消工作。此外,您可以考虑launch your work as unique-在大多数情况下它是更合适的方法。

09-08 08:23