Kotlin:如何在编译时检查类型对应的Loader是否已注册
编译时检查Loader注册的Kotlin方案
针对你遇到的「运行时才发现Loader未注册」的问题,以下是几种基于Kotlin特性的编译时检查方案,替代繁琐的逐个类型写方法的方式:
方案1:标记接口+泛型约束
通过定义一个空的标记接口,让所有注册了Loader的Realm模型实现它,再给ensureRealmObjectById方法添加泛型约束,从编译层面限制只能传入已标记的类型。
实现步骤:
- 定义标记接口
// 空接口,仅用于标记已注册Loader的模型 interface HasRegisteredLoader
- 让需要支持Loader的Realm模型实现该接口
class RealmCar : RealmObject(), HasRegisteredLoader class RealmCarModel : RealmObject(), HasRegisteredLoader
- 修改BatchRefreshService的方法,添加泛型约束
class BatchRefreshService { // 注册Loader时,仅允许传入实现了HasRegisteredLoader的类型(可选,进一步约束注册逻辑) fun <T : RealmObject & HasRegisteredLoader> registerLoader( clazz: KClass<T>, loader: (List<String>, Int) -> List<T> ) { // 原注册逻辑 } // 仅允许处理实现了HasRegisteredLoader的类型,编译时直接拦截非法调用 fun <T : RealmObject & HasRegisteredLoader> ensureRealmObjectById( realm: Realm, id: String ): T? { // 原逻辑:查DB/拉取数据并存库 } }
优点:实现简单,侵入性极低(仅需给模型加一个空接口),编译时直接报错,IDE会实时提示非法调用。
方案2:密封类约束
如果你的Realm模型类型是有限且相对固定的,可以用密封类统一管理所有支持Loader的模型,通过泛型约束限制调用范围。
实现步骤:
- 定义密封父类
sealed class LoadableRealmObject : RealmObject()
- 让支持Loader的模型继承该密封类
class RealmCar : LoadableRealmObject() class RealmCarModel : LoadableRealmObject()
- 修改服务方法的泛型约束
class BatchRefreshService { fun <T : LoadableRealmObject> registerLoader( clazz: KClass<T>, loader: (List<String>, Int) -> List<T> ) { // 原注册逻辑 } fun <T : LoadableRealmObject> ensureRealmObjectById( realm: Realm, id: String ): T? { // 原逻辑 } }
优点:类型约束更严格,IDE会自动提示所有可用的模型类型,避免手动传错;缺点是新增模型时需要修改密封类,扩展性稍差。
方案3:编译时注解处理器(KAPT)
如果不想修改模型的继承/实现结构,可以用Kotlin注解处理器(KAPT)在编译阶段扫描并检查Loader的注册情况。
实现步骤:
- 定义标记注解
@Target(AnnotationTarget.CLASS) @Retention(AnnotationRetention.SOURCE) annotation class RequiresLoader
- 给已注册Loader的模型添加注解
@RequiresLoader class RealmCar : RealmObject()
- 编写KAPT处理器:
- 扫描所有带有
@RequiresLoader的类,记录下来 - 扫描所有调用
ensureRealmObjectById的代码,检查传入的类型是否在记录列表中 - 若未找到匹配的标记,抛出编译警告或错误
- 扫描所有带有
优点:完全无侵入,不需要修改模型的结构;缺点是需要编写注解处理器,有一定学习成本,适合复杂场景。
内容的提问来源于stack exchange,提问作者Felipe Ribeiro R. Magalhaes
相关产品推荐
相关产品推荐

