Pager一般需要使用不同参数的同类型的ViewModel,使用hiltViewModel无法创建实例(hilt未提供带key实例化的方法),在不使用Hilt的情况下,viewModel是提供带key的方法的。
背景
最近在研究Hilt如何与Compose进行工作协作,发现有一个问题。viewModel方法提供了带key工作的方法,而hiltViewModel则没有这样的方法,这是十分不方便的。因为开发中,我们会经常遇到使用Pager的情况,而Pager中的子页面,使用的ViewModel往往是一个类型的带不同参。这样,hiltViewModel就无法适应这种情况,会出现几个子页面数据一模一样的问题。经过我不断的搜查网络上的资料,看到的有一个使用CompositionLocalProvider来提供几个子页面的ViewModelProviderOwner。但是这种方法会在hiltViewModel实例化你的PagerItemViewModel时报错无法实例化。
网上给出的🌰是这样的:
@hiltViewModel
class PagerViewModel @Inject constructor() : ViewModel(){
private var viewModelStores = mutableMapOf<Int, ViewModelStore>()
fun getViewModelStoreOwner(page: Int): ViewModelStoreOwner {
return object : ViewModelStoreOwner {
override val viewModelStore: ViewModelStore
get() {
var vms = viewModelStores[page]
if (vms == null) {
vms = ViewModelStore()
viewModelStores[page] = vms
}
return vms
}
}
}
}
@Composable
fun PagerView(val mainViewModel:PagerViewModel = hiltViewModel()){
HorizontalPager(
modifier = Modifier
.fillMaxSize(),
state = pagerState,
) { page ->
CompositionLocalProvider(LocalViewModelProviderOwner provides mainViewModel.getViewModelStoreOwner(page){
PagerItemView() //子视图
}
}
}
以上代码会出现报错,因为hiltViewModel无法初始化完成,无法创建ViewModel的实例。因为ViewModelProviderOwner不是StackNavEntry,hiltViewModel无法正常工作。
解决方案
经常尝试且失败后,我又查阅了很多资料,最终在bing国际版上发现compose官方的issue 里面有很多人同样遇到这样的问题且无法解决,找到官方看有什么方案提供。后来官方,给出了一个方案代码,如下:
/**
* 实例化带参数Key的HiltViewModel对象,[issue地址](https://github.com/google/dagger/issues/2328)
* @param key 参数key
*/
@Composable
inline fun <reified VM : ViewModel> hiltViewModel(key: String): VM {
val viewModelStoreOwner =
if (checkNotNull(LocalViewModelStoreOwner.current) is NavBackStackEntry) {
checkNotNull(LocalViewModelStoreOwner.current) { "ViewModelStoreOwner is null" }
} else null
return viewModel(
key = key,
factory = if (viewModelStoreOwner is NavBackStackEntry) {
HiltViewModelFactory(LocalContext.current, viewModelStoreOwner)
} else null
)
}
就这样,在Pager中使用hiltViewModel(key=name)方法完成ViewModel实例化。虽然官方提供了解决方案,但是在hilt-navigation:1.0.0版本中并不支持,1.1.0版本才开始支持,目前还是alpha版本,可以先用以上代码提供支持。
- 如果能帮到你,请给我点个赞支持一下,谢谢!