如何使用WorkManager创建通用NetworkRequestWorker?
复用CoroutineWorker处理网络请求的最佳实践
先澄清NowInAndroid的Repository传递问题
你看到的NowInAndroid示例中,Worker并非通过WorkRequest的Data传递Repository,而是通过**依赖注入(如Hilt)**注入到Worker构造函数中的。WorkManager允许通过自定义WorkerFactory创建Worker实例,DI框架会负责注入Repository这类依赖,不需要将其序列化传入Data。
核心抽象方案:泛型Worker + 请求处理器策略
要复用Worker处理不同网络请求,同时避免重复代码,推荐用泛型CoroutineWorker配合请求处理器接口的模式,既统一网络请求的核心逻辑,又能灵活扩展不同请求的业务操作。
1. 定义请求处理器接口
封装每个请求的核心逻辑:执行请求、成功回调、失败回调
interface NetworkRequestHandler<Request, Response> { // 执行具体网络请求 suspend fun executeRequest(request: Request): Result<Response> // 请求成功后的业务操作 suspend fun onSuccess(response: Response) // 请求失败后的处理逻辑 suspend fun onFailure(throwable: Throwable) }
2. 实现泛型基础Worker
统一处理参数解析、异常捕获、流程调度,避免重复编写Worker模板代码
class GenericNetworkWorker<Request, Response>( context: Context, params: WorkerParameters, private val handler: NetworkRequestHandler<Request, Response>, private val jsonConverter: JsonConverter // 封装Gson/Moshi等序列化工具 ) : CoroutineWorker(context, params) { override suspend fun doWork(): Result { return try { // 从WorkData中读取序列化后的请求参数 val requestJson = inputData.getString(KEY_REQUEST_PARAMS) ?: return Result.failure(workDataOf(KEY_ERROR to "缺少请求参数")) // 反序列化为请求实体类 val request = jsonConverter.fromJson(requestJson, Request::class.java) // 执行请求并处理结果 when (val responseResult = handler.executeRequest(request)) { is Result.Success -> { handler.onSuccess(responseResult.data) Result.success() } is Result.Failure -> { handler.onFailure(responseResult.exception) Result.failure(workDataOf(KEY_ERROR to responseResult.exception.message)) } } } catch (e: Exception) { handler.onFailure(e) Result.failure(workDataOf(KEY_ERROR to e.message)) } } companion object { const val KEY_REQUEST_PARAMS = "request_params" const val KEY_ERROR = "error_message" } }
3. 实现具体请求的处理器
比如登录请求的处理器,专注于该请求的业务逻辑
class LoginRequestHandler( private val authRepository: AuthRepository, private val userDataStore: UserDataStore ) : NetworkRequestHandler<LoginRequest, LoginResponse> { override suspend fun executeRequest(request: LoginRequest): Result<LoginResponse> { return authRepository.login(request) // 调用Repository的网络请求方法 } override suspend fun onSuccess(response: LoginResponse) { userDataStore.saveAuthToken(response.token) // 成功后保存Token } override suspend fun onFailure(throwable: Throwable) { Log.e("LoginWorker", "登录请求失败", throwable) // 失败后记录日志 } }
4. 用依赖注入绑定Worker
以Hilt为例,通过@HiltWorker注解让DI框架管理Worker实例,注入所需的处理器和序列化工具
@HiltWorker class LoginWorker @AssistedInject constructor( @Assisted context: Context, @Assisted params: WorkerParameters, private val loginHandler: LoginRequestHandler, private val jsonConverter: JsonConverter ) : GenericNetworkWorker<LoginRequest, LoginResponse>(context, params, loginHandler, jsonConverter)
5. 创建并执行WorkRequest
将请求参数序列化后传入WorkData,再构建WorkRequest
// 构造请求参数 val loginRequest = LoginRequest(username = "test_user", password = "123456") // 序列化请求参数 val requestJson = jsonConverter.toJson(loginRequest) // 组装WorkData val workData = workDataOf(GenericNetworkWorker.KEY_REQUEST_PARAMS to requestJson) // 创建WorkRequest并加入队列 val loginWorkRequest = OneTimeWorkRequestBuilder<LoginWorker>() .setInputData(workData) .build() WorkManager.getInstance(context).enqueue(loginWorkRequest)
替代方案:请求标识 + Repository驱动
如果请求参数可以通过Repository/本地数据源获取,也可以只传递请求标识(如REQUEST_TYPE字符串),Worker根据标识调用Repository对应方法:
class IdentifiedNetworkWorker( context: Context, params: WorkerParameters, private val authRepository: AuthRepository, private val userDataStore: UserDataStore ) : CoroutineWorker(context, params) { override suspend fun doWork(): Result { val requestType = inputData.getString(KEY_REQUEST_TYPE) ?: return Result.failure() return when (requestType) { "LOGIN" -> handleLoginRequest() "REFRESH_TOKEN" -> handleRefreshToken() else -> Result.failure() } } private suspend fun handleLoginRequest(): Result { // 从本地获取登录参数(比如DataStore) val loginParams = userDataStore.getPendingLoginParams() return try { val response = authRepository.login(loginParams) userDataStore.saveAuthToken(response.token) Result.success() } catch (e: Exception) { Log.e("LoginWorker", "登录失败", e) Result.failure() } } companion object { const val KEY_REQUEST_TYPE = "request_type" } }
方案对比
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 泛型Worker+处理器 | 代码复用率高,逻辑解耦 | 需要依赖DI框架,稍显复杂 | 多类型网络请求场景 |
| 单独Worker类 | 逻辑直观,无需额外封装 | 代码重复度高 | 少量简单网络请求场景 |
| 请求标识+Repository | 无需传递复杂参数 | 依赖本地数据源存储参数 | 参数可本地获取的请求 |
内容的提问来源于stack exchange,提问作者Sohel Shaikh
相关产品推荐
相关产品推荐

