You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Koin Factory生成的AdRepository参数被缓存?如何重新调用?

Koin带参数Repository缓存问题排查与解决

问题描述

我在Koin模块中定义了需要参数的AdRepository:

factory<AdRepository> { params ->
    DefaultAdRepository(
        inputAdId = params.get(),
        api = get(),
        log = get(),
        mapper = get()
    )
}

接着在ViewModel中通过parametersOf()获取该Repository:

viewModel { params ->
    val adId: Long = params.get()
    AdvertisementDetailViewModel(
        inputAdId = adId,
        adRepository = get(parameters = { parametersOf(adId) }),
        log = get()
    )
}

但实际运行时出现异常:每次进入/离开页面导致ViewModel重建时,adRepository的参数并未更新——Repository的init块仅在第一次实例化ViewModel时执行,后续即使ViewModel参数正确,Repository始终保留第一次的参数值。手动构造Repository可解决问题,但希望通过Koin原生功能实现带参数ViewModel对应带参数Repository的注入。

问题原因

Koin在ViewModel的专属作用域(ViewModelScope)内,默认会缓存通过get()获取的factory类型依赖实例。尽管factory本身设计为每次调用生成新实例,但当Koin判断当前作用域内已存在同类型依赖时,会忽略参数变化直接复用旧实例。当ViewModel因页面进出重建时,若Koin未识别到作用域的变更,就会导致Repository复用旧参数的实例。

解决方案

1. 明确参数类型,避免解析错误

在Repository的factory定义中明确指定参数类型,确保Koin正确解析参数:

factory<AdRepository> { params ->
    DefaultAdRepository(
        inputAdId = params.get<Long>(), // 显式指定参数类型
        api = get(),
        log = get(),
        mapper = get()
    )
}

2. 为Repository添加唯一标识

通过named限定符结合参数生成唯一标识,让Koin区分不同参数的Repository实例:

// 定义带限定符的factory
factory<AdRepository>(qualifier = named { params -> "ad_repo_${params.get<Long>()}" }) { params ->
    DefaultAdRepository(
        inputAdId = params.get<Long>(),
        api = get(),
        log = get(),
        mapper = get()
    )
}

// ViewModel中获取对应标识的Repository
viewModel { params ->
    val adId: Long = params.get()
    AdvertisementDetailViewModel(
        inputAdId = adId,
        adRepository = get(named("ad_repo_$adId"), parameters = { parametersOf(adId) }),
        log = get()
    )
}

3. 将Repository改为scoped绑定

由于每个ViewModel对应独立的ViewModelScope,将Repository改为scoped绑定后,每个ViewModel作用域内会生成唯一的Repository实例,ViewModel重建时会自动创建新的Repository:

// 改为scoped绑定
scoped<AdRepository> { params ->
    DefaultAdRepository(
        inputAdId = params.get<Long>(),
        api = get(),
        log = get(),
        mapper = get()
    )
}

// ViewModel中获取方式不变
viewModel { params ->
    val adId: Long = params.get()
    AdvertisementDetailViewModel(
        inputAdId = adId,
        adRepository = get(parameters = { parametersOf(adId) }),
        log = get()
    )
}

4. 强制获取新实例

使用Koin的getNew()方法替代get(),强制每次调用factory生成新实例:

viewModel { params ->
    val adId: Long = params.get()
    AdvertisementDetailViewModel(
        inputAdId = adId,
        adRepository = getNew(parameters = { parametersOf(adId) }),
        log = get()
    )
}

内容的提问来源于stack exchange,提问作者Grzegorz Adam Hankiewicz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 22:52:40