DelegatingWorker

class DelegatingWorker(appContext: Context, workerParams: WorkerParameters) : CoroutineWorker

A proxy Worker that delegates work to another CoroutineWorker created via HiltWorkerFactory.

Why This Pattern Exists

Problem

WorkManager creates Worker instances using reflection, which prevents Hilt from automatically injecting dependencies. The standard solution requires configuring a custom WorkManager initializer in the app module, which creates tight coupling and violates separation of concerns.

Solution

This delegating pattern allows library modules (like :sync) to define Workers with injected dependencies WITHOUT requiring the app module to configure WorkManager. Instead:

  1. The app module enqueues a generic DelegatingWorker

  2. DelegatingWorker receives the actual Worker class name via input data

  3. DelegatingWorker uses Hilt's entry point to get HiltWorkerFactory

  4. HiltWorkerFactory creates the real Worker with all dependencies injected

  5. DelegatingWorker delegates all work to the real Worker

Benefits

  • Modular: Library modules can define Workers without app module configuration

  • Type-safe: Compile-time verification of Worker classes via delegatedData() extension

  • Clean: App module doesn't need custom WorkManager initialization

  • Testable: Real Workers can be tested independently with mock dependencies

Usage Pattern

// 1. Define a Worker in a library module with dependencies
@HiltWorker
class SyncWorker @AssistedInject constructor(
@Assisted appContext: Context,
@Assisted params: WorkerParameters,
private val repository: Repository // Injected by Hilt!
) : CoroutineWorker(appContext, params) {
override suspend fun doWork(): Result { /* ... */}
}

// 2. Enqueue DelegatingWorker with metadata pointing to the real Worker
val workRequest = OneTimeWorkRequestBuilder<DelegatingWorker>()
.setInputData(SyncWorker::class.delegatedData())
.build()

WorkManager.getInstance(context).enqueue(workRequest)

Architecture Decision

This pattern was chosen over custom WorkManager configuration because:

  • It keeps WorkManager initialization in the app module simple

  • Library modules remain self-contained and reusable

  • No need for app module to know about library module Workers

  • Follows separation of concerns principle

Parameters

appContext

The application context provided by WorkManager

workerParams

The worker parameters containing input data with the delegate Worker class name

See also

Constructors

Link copied to clipboard
constructor(appContext: Context, workerParams: WorkerParameters)

Properties

Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
open val coroutineContext: CoroutineDispatcher
Link copied to clipboard
val foregroundInfoAsync: com/google/common/util/concurrent/ListenableFuture<androidx/work/ForegroundInfo>
Link copied to clipboard
val id: @NonNull UUID
Link copied to clipboard
val inputData: @NonNull Data
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
@get:RequiresApi(value = 28)
val network: @Nullable Network?
Link copied to clipboard
@get:IntRange(from = 0)
val runAttemptCount: Int
Link copied to clipboard
@get:RequiresApi(value = 31)
val stopReason: Int
Link copied to clipboard
val tags: @NonNull Set<String?>
Link copied to clipboard
open val taskExecutor: @NonNull TaskExecutor
Link copied to clipboard
@get:RequiresApi(value = 24)
val triggeredContentAuthorities: @NonNull List<String?>
Link copied to clipboard
@get:RequiresApi(value = 24)
val triggeredContentUris: @NonNull List<Uri?>
Link copied to clipboard

Functions

Link copied to clipboard
open suspend override fun doWork(): ListenableWorker.Result

Delegates the actual work execution to the real Worker.

Link copied to clipboard
open suspend override fun getForegroundInfo(): ForegroundInfo

Delegates foreground info retrieval to the actual Worker.

Link copied to clipboard
override fun getForegroundInfoAsync(): com/google/common/util/concurrent/ListenableFuture<androidx/work/ForegroundInfo>
Link copied to clipboard
override fun onStopped()
Link copied to clipboard
suspend fun setForeground(foregroundInfo: ForegroundInfo)
Link copied to clipboard
fun setForegroundAsync(foregroundInfo: @NonNull ForegroundInfo): @EnhancedNullability @R|org/jspecify/annotations/NonNull|() com/google/common/util/concurrent/ListenableFuture
Link copied to clipboard
suspend fun setProgress(data: Data)
Link copied to clipboard
open fun setProgressAsync(data: @NonNull Data): @EnhancedNullability @R|org/jspecify/annotations/NonNull|() com/google/common/util/concurrent/ListenableFuture
Link copied to clipboard
Link copied to clipboard
override fun startWork(): com/google/common/util/concurrent/ListenableFuture<androidx/work/ListenableWorker.Result>
Link copied to clipboard