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

Android中如何将依赖注入管控的仓库传入子视图模型

Android中如何将依赖注入管控的仓库传入子视图模型

嘿,我来帮你搞定这个问题!从你描述的场景来看,你有一个Android应用的列表页面,每个AppListItemView对应自己的AppListItemViewModel,现在需要把通过依赖注入管理的仓库传递给这些子视图模型对吧?我给你分享几种实用的方案:

方案一:构造函数直接传入(简单直接)

首先,你需要修改AppListItemViewModel的构造函数,让它接收你的仓库实例。假设你的仓库类是AppRepository,调整后的ViewModel代码大概是这样:

import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import com.mikewarren.speakify.data.UserAppModel

class AppListItemViewModel(
    private val appRepository: AppRepository, // 注入的仓库
    val userAppModel: UserAppModel
) : ViewModel() {
    // 你的flag状态
    var someFlag by mutableStateOf(false)

    // 现在你可以直接在ViewModel里用仓库做操作了,比如:
    fun updateAppStatus() {
        appRepository.updateApp(userAppModel.id, someFlag)
    }
}

接下来,在父Composable或者父ViewModel中,你肯定已经通过依赖注入拿到了AppRepository实例(比如用Hilt的@Inject或者其他DI框架),然后在创建列表项ViewModel的时候直接把仓库传进去:

@Composable
fun AppListScreen(
    // 这里通过Hilt注入仓库实例
    appRepository: AppRepository = hiltViewModel()
) {
    // 从仓库获取用户应用列表数据
    val userAppList = appRepository.getUserApps()

    LazyColumn {
        items(userAppList) { appModel ->
            AppListItemView(
                viewModel = AppListItemViewModel(appRepository, appModel)
            )
        }
    }
}

⚠️ 注意:这种方式直接new ViewModel的话,它不会被ViewModelStore管理,意味着配置变化(比如旋转屏幕)时ViewModel会被重建。如果你的列表项ViewModel不需要在配置变化时保留状态,这个方案完全够用;如果需要保留状态,就看下面的方案。

方案二:结合ViewModel工厂+依赖注入(支持生命周期管理)

如果你的子ViewModel需要遵循Android的ViewModel生命周期规则,那最好用ViewModelProvider的工厂来创建,结合依赖注入框架(比如Hilt)来注入仓库。

首先,给AppListItemViewModel添加@HiltViewModel注解,构造函数用@Inject标记仓库参数,同时我们可以用SavedStateHandle来传递列表项的UserAppModel相关信息(比如ID):

import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.mikewarren.speakify.data.UserAppModel
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import javax.inject.Inject

@HiltViewModel
class AppListItemViewModel @Inject constructor(
    private val appRepository: AppRepository,
    private val savedStateHandle: SavedStateHandle
) : ViewModel() {
    // 从SavedStateHandle获取传递过来的应用ID
    private val appId = savedStateHandle.get<Int>("app_id") ?: 0
    var userAppModel by mutableStateOf(UserAppModel())
    var someFlag by mutableStateOf(false)

    init {
        // 初始化时从仓库加载对应的应用数据
        viewModelScope.launch {
            userAppModel = appRepository.getAppById(appId)
            someFlag = userAppModel.isEnabled // 假设你的模型里有这个状态
        }
    }

    fun toggleFlag() {
        someFlag = !someFlag
        viewModelScope.launch {
            appRepository.updateAppFlag(appId, someFlag)
        }
    }
}

然后,在列表项的Composable中,通过viewModel()函数获取ViewModel实例,同时传递应用ID到SavedStateHandle:

@Composable
fun AppListItemView(appModel: UserAppModel) {
    val viewModel: AppListItemViewModel = viewModel(
        factory = defaultViewModelProviderFactory,
        key = "app_item_${appModel.id}" // 用ID作为key,确保每个列表项有独立的ViewModel
    ) {
        // 把应用ID存入SavedStateHandle
        savedStateHandle["app_id"] = appModel.id
    }

    // 渲染你的列表项UI,比如:
    Row {
        Text(text = appModel.name)
        Checkbox(checked = viewModel.someFlag, onCheckedChange = { viewModel.toggleFlag() })
    }
}

这种方案的好处是,每个列表项的ViewModel都会被ViewModelStore管理,配置变化时状态不会丢失,而且仓库的注入完全由Hilt管控,符合依赖注入的最佳实践。

小提醒

如果你的列表项逻辑比较简单,其实也可以不用子ViewModel,直接在Composable中调用仓库方法,用remember或者mutableStateOf来管理状态。但如果列表项有复杂的异步操作、状态逻辑,子ViewModel还是更合适的选择。

备注:内容来源于stack exchange,提问作者Mike Warren

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.13 17:04:38