如何限制基于Jetpack指南开发的NetworkBoundResource库仅支持Room
实现限制仅支持Room的两种可行方案
方案1:运行时注解校验(无侵入,开发期快速发现问题)
原理是Room的实体类必须标注@Entity注解,我们可以通过Kotlin反射校验传入的ResultType是否带有该注解,不匹配直接抛出异常。
需要先添加Room核心依赖以引用@Entity注解,再修改原函数代码:
import androidx.room.Entity import kotlin.reflect.full.findAnnotation // 给ResultType添加reified修饰以获取其类型信息 inline fun <reified ResultType, RequestType> networkBoundResource( crossinline loadFromDb: () -> Flow<ResultType>, crossinline netWorkRequest: suspend () -> Response<RequestType>, crossinline saveCall: suspend (Response<RequestType>) -> Unit ): Flow<Resource<ResultType>> = flow { // 入口处校验是否为Room实体 if (ResultType::class.findAnnotation<Entity>() == null) { throw IllegalArgumentException("NetworkBoundResource 仅支持Room数据库实体类,请确保ResultType标注了@Entity注解") } emit(Resource.Loading(loadFromDb().firstOrNull())) val netWorkResponse = netWorkRequest() emitAll( if (netWorkResponse.isSuccessful) { saveCall(netWorkResponse) loadFromDb().map { Resource.Success(it) } } else { loadFromDb().map { Resource.Error("Error", it) } } ) }.flowOn(Dispatchers.IO)
该方案不需要使用者修改现有实体类代码,只要调用时传入非Room实体就会直接崩溃,开发测试阶段就能快速发现误用。
方案2:编译时标记接口约束(更安全,编译期拦截误用)
如果想要更早拦截错误,可通过自定义标记接口+泛型上界约束实现编译期校验:
- 首先在库中定义空标记接口:
interface RoomEntityMarker
- 要求所有使用该库的Room实体类实现该接口:
import androidx.room.Entity @Entity data class User( @PrimaryKey val id: Int, val name: String ) : RoomEntityMarker
- 修改networkBoundResource的泛型约束,限制ResultType必须实现该标记接口:
inline fun <ResultType : RoomEntityMarker, RequestType> networkBoundResource( crossinline loadFromDb: () -> Flow<ResultType>, crossinline netWorkRequest: suspend () -> Response<RequestType>, crossinline saveCall: suspend (Response<RequestType>) -> Unit ): Flow<Resource<ResultType>> = flow { // 原有逻辑不变 emit(Resource.Loading(loadFromDb().firstOrNull())) val netWorkResponse = netWorkRequest() emitAll( if (netWorkResponse.isSuccessful) { saveCall(netWorkResponse) loadFromDb().map { Resource.Success(it) } } else { loadFromDb().map { Resource.Error("Error", it) } } ) }.flowOn(Dispatchers.IO)
如果要完全杜绝使用者给非Room实体添加该标记接口,可搭配简单的KSP注解处理器,编译时扫描所有RoomEntityMarker的实现类,检查是否带有@Entity注解,不匹配直接抛出编译错误。
内容的提问来源于stack exchange,提问作者Nicote Ool
相关产品推荐
相关产品推荐

