WorkerFactory.kt
/*
* Copyright 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.work
import android.content.Context
import androidx.annotation.RestrictTo
/**
* A factory object that creates [ListenableWorker] instances. The factory is invoked every
* time a work runs. You can override the default implementation of this factory by manually
* initializing [WorkManager] (see [WorkManager.initialize] and
* specifying a new WorkerFactory in [Configuration.Builder.setWorkerFactory].
*/
abstract class WorkerFactory {
/**
* Override this method to implement your custom worker-creation logic. Use
* [Configuration.Builder.setWorkerFactory] to use your custom class.
*
* Throwing an [Exception] here will crash the application. If a [WorkerFactory]
* is unable to create an instance of the [ListenableWorker], it should return `null` so
* it can delegate to the default [WorkerFactory].
*
* Returns a new instance of the specified `workerClassName` given the arguments. The
* returned worker must be a newly-created instance and must not have been previously returned
* or invoked by WorkManager. Otherwise, WorkManager will throw an
* [IllegalStateException].
*
* @param appContext The application context
* @param workerClassName The class name of the worker to create
* @param workerParameters Parameters for worker initialization
* @return A new [ListenableWorker] instance of type `workerClassName`, or
* `null` if the worker could not be created
*/
abstract fun createWorker(
appContext: Context,
workerClassName: String,
workerParameters: WorkerParameters
): ListenableWorker?
/**
* Returns a new instance of the specified `workerClassName` given the arguments. If no
* worker is found, default reflection-based code will be used to instantiate the worker with
* the current ClassLoader. The returned worker should be a newly-created instance and must not
* have been previously returned or used by WorkManager.
*
* @param appContext The application context
* @param workerClassName The class name of the worker to create
* @param workerParameters Parameters for worker initialization
* @return A new [ListenableWorker] instance of type `workerClassName`, or
* `null` if the worker could not be created
* @throws IllegalStateException when the [WorkerFactory] returns an instance
* of the [ListenableWorker] which is used.
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
fun createWorkerWithDefaultFallback(
appContext: Context,
workerClassName: String,
workerParameters: WorkerParameters
): ListenableWorker? {
var worker = createWorker(appContext, workerClassName, workerParameters)
if (worker == null) {
// Fallback to reflection
try {
Class.forName(workerClassName).asSubclass(ListenableWorker::class.java)
} catch (throwable: Throwable) {
Logger.get().error(TAG, "Invalid class: $workerClassName", throwable)
null
}?.let { clazz ->
try {
val constructor = clazz.getDeclaredConstructor(
Context::class.java, WorkerParameters::class.java
)
worker = constructor.newInstance(appContext, workerParameters)
} catch (e: Throwable) {
Logger.get().error(TAG, "Could not instantiate $workerClassName", e)
}
}
}
if (worker?.isUsed == true) {
val message = "WorkerFactory (${javaClass.name}) returned an instance of" +
" a ListenableWorker ($workerClassName) which has already been invoked. " +
"createWorker() must always return a new instance of a ListenableWorker."
throw IllegalStateException(message)
}
return worker
}
}
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
object DefaultWorkerFactory : WorkerFactory() {
override fun createWorker(
appContext: Context,
workerClassName: String,
workerParameters: WorkerParameters
) = null
}
private val TAG = Logger.tagWithPrefix("WorkerFactory")