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

2023年Android Hilt注入辅助参数至ViewModel的更优方案问询

问题

在2023年,除了已知的那种方式外,有没有更优或更少样板代码的方案,能将Assisted参数注入到ViewModel的构造方法中?

当前ViewModel实现代码:

class PlantDetailViewModel @AssistedInject constructor(
    plantRepository: PlantRepository,
    @Assisted private val savedStateHandle: SavedStateHandle,
    @Assisted private val plantId: String
) : ViewModel() {

    @AssistedFactory
    interface PlantDetailViewModelFactory {
        fun create(handle: SavedStateHandle, plantId: String): PlantDetailViewModel
    }

    companion object {
        fun provideFactory(
            assistedFactory: PlantDetailViewModelFactory,
            owner: SavedStateRegistryOwner,
            defaultArgs: Bundle? = null,
            plantId: String
        ): AbstractSavedStateViewModelFactory = object : AbstractSavedStateViewModelFactory(owner, defaultArgs) {
            @Suppress("UNCHECKED_CAST")
            override fun <T : ViewModel?> create(key: String, modelClass: Class<T>, handle: SavedStateHandle): T {
                return assistedFactory.create(handle, plantId) as T
            }
        }
    }
}

Fragment中的调用代码:

@AndroidEntryPoint
class PlantDetailFragment : Fragment() {

    private val args: PlantDetailFragmentArgs by navArgs()

    @Inject
    lateinit var plantDetailViewModelFactory: PlantDetailViewModelFactory

    private val plantDetailViewModel: PlantDetailViewModel by viewModels {
        PlantDetailViewModel.provideFactory(plantDetailViewModelFactory, this, arguments, args.plantId)
    }
}

更简洁的实现方案

方案1:利用Hilt的@HiltViewModel配合SavedStateHandle传递参数

如果项目已经接入Hilt,可以直接借助SavedStateHandle传递Assisted参数,完全省去手动创建工厂类的样板代码:

  1. 修改ViewModel:
@HiltViewModel
class PlantDetailViewModel @Inject constructor(
    plantRepository: PlantRepository,
    private val savedStateHandle: SavedStateHandle
) : ViewModel() {
    // 直接从SavedStateHandle中获取plantId
    private val plantId: String = savedStateHandle.get<String>("plantId")!!
}
  1. Fragment中调用:
@AndroidEntryPoint
class PlantDetailFragment : Fragment() {
    private val args: PlantDetailFragmentArgs by navArgs()
    
    // 通过默认创建扩展传递参数到SavedStateHandle
    private val plantDetailViewModel: PlantDetailViewModel by hiltViewModel(
        extras = defaultViewModelCreationExtras.apply {
            setSavedStateHandleArgs(mapOf("plantId" to args.plantId))
        }
    )
}

方案2:用Kotlin扩展函数简化工厂创建逻辑

如果必须保留@AssistedInject的方式,可以把通用的工厂创建逻辑抽成扩展函数,减少ViewModel内的重复代码:

  1. 定义通用扩展函数:
inline fun <reified T : ViewModel> createAssistedSavedStateFactory(
    owner: SavedStateRegistryOwner,
    defaultArgs: Bundle? = null,
    crossinline create: (SavedStateHandle) -> T
): AbstractSavedStateViewModelFactory {
    return object : AbstractSavedStateViewModelFactory(owner, defaultArgs) {
        @Suppress("UNCHECKED_CAST")
        override fun <VM : ViewModel?> create(key: String, modelClass: Class<VM>, handle: SavedStateHandle): VM {
            return create(handle) as VM
        }
    }
}
  1. 修改ViewModel(移除companion内的provideFactory方法):
class PlantDetailViewModel @AssistedInject constructor(
    plantRepository: PlantRepository,
    @Assisted private val savedStateHandle: SavedStateHandle,
    @Assisted private val plantId: String
) : ViewModel() {

    @AssistedFactory
    interface PlantDetailViewModelFactory {
        fun create(handle: SavedStateHandle, plantId: String): PlantDetailViewModel
    }
}
  1. Fragment中调用:
@AndroidEntryPoint
class PlantDetailFragment : Fragment() {
    private val args: PlantDetailFragmentArgs by navArgs()
    
    @Inject
    lateinit var plantDetailViewModelFactory: PlantDetailViewModelFactory

    private val plantDetailViewModel: PlantDetailViewModel by viewModels {
        createAssistedSavedStateFactory(this, arguments) { handle ->
            plantDetailViewModelFactory.create(handle, args.plantId)
        }
    }
}

方案3:借助AssistedInject的Kotlin委托库简化调用

引入AssistedInject的Kotlin扩展库,可以进一步简化Fragment中的ViewModel初始化:

先添加依赖:

implementation "com.squareup.inject:assisted-inject-ktx:0.7.0"

然后Fragment中直接使用委托:

@AndroidEntryPoint
class PlantDetailFragment : Fragment() {
    private val args: PlantDetailFragmentArgs by navArgs()
    
    @Inject
    lateinit var factory: PlantDetailViewModelFactory

    private val viewModel: PlantDetailViewModel by assistedViewModels {
        factory.create(savedStateHandle, args.plantId)
    }
}

内容的提问来源于stack exchange,提问作者Nexussim Lements

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 06:52:46