Pager一般需要使用不同參數(shù)的同類型的ViewModel,使用hiltViewModel無法創(chuàng)建實例(hilt未提供帶key實例化的方法),在不使用Hilt的情況下,viewModel是提供帶key的方法的。
背景
最近在研究Hilt如何與Compose進行工作協(xié)作,發(fā)現(xiàn)有一個問題。viewModel方法提供了帶key工作的方法,而hiltViewModel則沒有這樣的方法,這是十分不方便的。因為開發(fā)中,我們會經(jīng)常遇到使用Pager的情況,而Pager中的子頁面,使用的ViewModel往往是一個類型的帶不同參。這樣,hiltViewModel就無法適應這種情況,會出現(xiàn)幾個子頁面數(shù)據(jù)一模一樣的問題。經(jīng)過我不斷的搜查網(wǎng)絡上的資料,看到的有一個使用CompositionLocalProvider來提供幾個子頁面的ViewModelProviderOwner。但是這種方法會在hiltViewModel實例化你的PagerItemViewModel時報錯無法實例化。
網(wǎng)上給出的??是這樣的:
@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() //子視圖
}
}
}
以上代碼會出現(xiàn)報錯,因為hiltViewModel無法初始化完成,無法創(chuàng)建ViewModel的實例。因為ViewModelProviderOwner不是StackNavEntry,hiltViewModel無法正常工作。
解決方案
經(jīng)常嘗試且失敗后,我又查閱了很多資料,最終在bing國際版上發(fā)現(xiàn)compose官方的issue 里面有很多人同樣遇到這樣的問題且無法解決,找到官方看有什么方案提供。后來官方,給出了一個方案代碼,如下:
/**
* 實例化帶參數(shù)Key的HiltViewModel對象,[issue地址](https://github.com/google/dagger/issues/2328)
* @param key 參數(shù)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版本,可以先用以上代碼提供支持。
- 如果能幫到你,請給我點個贊支持一下,謝謝!