客户端调用WorkManager.initialize()

时间:2019-10-11 14:50:32

标签: android android-workmanager

我正在编写一个使用WorkManager的Android库。在代码中的某处,我这样调用:

val uploadTripRequest = OneTimeWorkRequest.Builder(UploadTripWorker::class.java)
    .setConstraints(someConstraints)
    .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, OneTimeWorkRequest.MIN_BACKOFF_MILLIS, TimeUnit.MILLISECONDS)
    .build()

WorkManager.getInstance(context)
    .enqueueUniqueWork(WORKER_NAME, ExistingWorkPolicy.REPLACE, uploadTripRequest)

在我的build.gradle中,我有:implementation 'androidx.work:work-runtime:2.2.0'

通常,一切正常。客户端应用调用https://developer.android.com/reference/kotlin/androidx/work/WorkManager.html#initialize时会出现问题,例如:

WorkManager.initialize(context, Configuration.Builder().setWorkerFactory(myWorkerFactory).build())

调用此命令时,我的库中的WorkManager无法正常工作。 doWork方法未在我的UploadTripWorker上调用,但在客户端的myWorkerFactory提供的工作程序上执行。

从我的角度来看,WorkManager在库中是不可用的,因为它是单例,并且有人可以通过initialize方法更改其行为。但我希望我错了。

有什么办法可以解决这个问题?当然,我不能对所有客户说不要使用WorkManager.initialize()方法。

2 个答案:

答案 0 :(得分:1)

WorkManager v2.1引入了DelegatingWorkerFactory类,可以在这些情况下提供帮助。

正如您所说的WorkManager是单例的那样,它仍然需要应用程序开发人员以正确的方式实现它。

关键点在于,如果应用程序需要自定义初始化和自定义WorkerFactory,则应使用DelegatingWorkerFactory,然后add是它自己的WorkerFactory。

这里的关键点是应用程序的WorkerFactory应该检查worker类的名称,以确保它是正确的(通常在构造函数中注入一些参数)。如果该类名不是应用程序所期望的名称,则它只能返回null,而DelegatingWorkerFactory将注意找到要实例化的正确的工人类。

类似的东西(在应用程序代码中):

class MyWorkerFactory(
    private val myInjectedParam: InjectedParam
) : WorkerFactory() {

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

        return when (workerClassName) {
            MyWorker::class.java.name ->
                MyWorker(appContext, workerParameters, myInjectedParam)
            else ->
                // Return null, so that the base class can delegate to the default WorkerFactory.
                null
        }
    }
}

然后,应用程序需要使用以下命令将此WorkerFactory添加到已设置为自定义WorkerFactory的DelegatingWorkerFactory中:

private fun initializeWorkManager (myInjectedParam: MyInjectedParam): WorkManager
{ 
    val appContext = getApplication<MyApplication>()
    val factory = appContext.workManagerConfiguration.workerFactory
            as DelegatingWorkerFactory
    factory.addFactory(MyWorkerFactory(myInjectedParam))

    return WorkManager.getInstance(appContext)
}

在应用程序类中,您拥有:

class MainApplication : Application(), Configuration.Provider {

    val delegatingWorkerFactory: DelegatingWorkerFactory

    // Setup custom configuration for WorkManager with a DelegatingWorkerFactory
    override fun getWorkManagerConfiguration(): Configuration {
        return Configuration.Builder()
            .setMinimumLoggingLevel(android.util.Log.INFO)
            .setWorkerFactory(delegatingWorkerFactory)
            .build()
    }
}

答案 1 :(得分:0)

如果在库项目中有Worker和WorkerFactory,则在库清单中禁用默认的初始化程序似乎可以解决问题。由于库将具有与应用程序不同的程序包,因此除非您将其禁用,否则似乎会触发默认的初始化程序。

<provider android:name="androidx.work.impl.WorkManagerInitializer"
          android:authorities="<library's package>.analytics.workmanager-init"
          tools:node="remove" />

对我有用的设置。

我的应用程序包含:

  • 配置/提供程序
  • DelegatingWorkerFactory()设置为上述配置

我的图书馆包含:

  • 工人
  • WorkerFactory
  • WorkRequestBuilder
  • 满足工作要求

但是令我感兴趣的是WorkerFactory源代码中的此注释:

@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)

不确定是否应该警告我从另一个包中调用此方法。