jetpack compose 传递参数给 viewModel
jetpack compose pass parameter to viewModel
如何在 jetpack compose 中将参数传递给 viewModel?
这是我的可组合项
@Composable
fun UsersList() {
val myViewModel: MyViewModel = viewModel("db2name") // pass param like this
}
这是视图模型
class MyViewModel(private val dbname) : ViewModel() {
private val users: MutableLiveData<List<User>> by lazy {
MutableLiveData<List<User>>().also {
loadUsers()
}
}
fun getUsers(): LiveData<List<User>> {
return users
}
private fun loadUsers() {
// Do an asynchronous operation to fetch users.
}
}
您需要像这样创建一个工厂来将动态参数传递给 ViewModel:
class MyViewModelFactory(private val dbname: String) :
ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel?> create(modelClass: Class<T>): T = MyViewModel(dbname) as T
}
然后在可组合函数中像这样使用您的工厂:
@Composable
fun UsersList() {
val myViewModel: MyViewModel =
viewModel(factory = MyViewModelFactory("db2name")) // pass param like this
}
现在您可以访问 ViewModel 中的 dbname 参数:
class MyViewModel(private val dbname) : ViewModel() {
// ...rest of the viewModel logics here
}
通常情况下,您不需要这样做。在 android 中,MVVM 视图模型通过依赖注入从存储库中获取数据。
这是推荐的 android 架构的官方文档:https://developer.android.com/jetpack/guide#recommended-app-arch
正如@Secret Keeper 提到的,您需要创建工厂。
If your ViewModel has dependencies, viewModel() takes an optional
ViewModelProvider.Factory as a parameter.
class MyViewModelFactory(
private val dbname: String
) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(MyViewModel::class.java)) {
return MyViewModel(dbname) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
}
要创建您的 viewModel,您需要传递可选参数。在您的可组合项中,您可以执行类似的操作。
val viewModel: MyViewModel = viewModel(
factory = MyViewModelFactory(
dbname = "myDbName"
)
这里有一些 Jetpack Compose/Kotlin-specific 实现相同语法的语法:
ui/settings/SettingsViewModel.kt
class SettingsViewModel(
private val settingsRepository: SettingsRepository
) : ViewModel() {
/* Your implementation */
}
class SettingsViewModelFactory(
private val settingsRepository: SettingsRepository
) : ViewModelProvider.Factory {
override fun <T : ViewModel> create( modelClass: Class<T> ): T {
if( modelClass.isAssignableFrom( SettingsViewModel::class.java ) ) {
@Suppress( "UNCHECKED_CAST" )
return SettingsViewModel( settingsRepository ) as T
}
throw IllegalArgumentException( "Unknown ViewModel Class" )
}
}
然后:
MainActivity.kt
/* dataStore by preferencesDataStore */
class MainActivity : ComponentActivity() {
private lateinit var settingsRepository: SettingsRepository
// Here we instantiate our ViewModel leveraging delegates and
// a trailing lambda
private val settingsViewModel by viewModels<SettingsViewModel> {
SettingsViewModelFactory(
settingsRepository
)
}
/* onCreate -> setContent -> etc */
}
其他解决方案可行,但您必须为每个 ViewModel 创建一个工厂,这似乎有点过分了。
比较通用的方案是这样的:
inline fun <VM : ViewModel> viewModelFactory(crossinline f: () -> VM) =
object : ViewModelProvider.Factory {
override fun <T : ViewModel> create(aClass: Class<T>):T = f() as T
}
并像这样使用它:
@Composable
fun MainScreen() {
val viewModel: MyViewModel = viewModel(factory = viewModelFactory {
MyViewModel("Test Name")
})
}
对于这样的 ViewModel:
class MyViewModel(
val name: String
):ViewModel() {}
如何在 jetpack compose 中将参数传递给 viewModel?
这是我的可组合项
@Composable
fun UsersList() {
val myViewModel: MyViewModel = viewModel("db2name") // pass param like this
}
这是视图模型
class MyViewModel(private val dbname) : ViewModel() {
private val users: MutableLiveData<List<User>> by lazy {
MutableLiveData<List<User>>().also {
loadUsers()
}
}
fun getUsers(): LiveData<List<User>> {
return users
}
private fun loadUsers() {
// Do an asynchronous operation to fetch users.
}
}
您需要像这样创建一个工厂来将动态参数传递给 ViewModel:
class MyViewModelFactory(private val dbname: String) :
ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel?> create(modelClass: Class<T>): T = MyViewModel(dbname) as T
}
然后在可组合函数中像这样使用您的工厂:
@Composable
fun UsersList() {
val myViewModel: MyViewModel =
viewModel(factory = MyViewModelFactory("db2name")) // pass param like this
}
现在您可以访问 ViewModel 中的 dbname 参数:
class MyViewModel(private val dbname) : ViewModel() {
// ...rest of the viewModel logics here
}
通常情况下,您不需要这样做。在 android 中,MVVM 视图模型通过依赖注入从存储库中获取数据。
这是推荐的 android 架构的官方文档:https://developer.android.com/jetpack/guide#recommended-app-arch
正如@Secret Keeper 提到的,您需要创建工厂。
If your ViewModel has dependencies, viewModel() takes an optional ViewModelProvider.Factory as a parameter.
class MyViewModelFactory(
private val dbname: String
) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(MyViewModel::class.java)) {
return MyViewModel(dbname) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
}
要创建您的 viewModel,您需要传递可选参数。在您的可组合项中,您可以执行类似的操作。
val viewModel: MyViewModel = viewModel(
factory = MyViewModelFactory(
dbname = "myDbName"
)
这里有一些 Jetpack Compose/Kotlin-specific 实现相同语法的语法:
ui/settings/SettingsViewModel.kt
class SettingsViewModel(
private val settingsRepository: SettingsRepository
) : ViewModel() {
/* Your implementation */
}
class SettingsViewModelFactory(
private val settingsRepository: SettingsRepository
) : ViewModelProvider.Factory {
override fun <T : ViewModel> create( modelClass: Class<T> ): T {
if( modelClass.isAssignableFrom( SettingsViewModel::class.java ) ) {
@Suppress( "UNCHECKED_CAST" )
return SettingsViewModel( settingsRepository ) as T
}
throw IllegalArgumentException( "Unknown ViewModel Class" )
}
}
然后:
MainActivity.kt
/* dataStore by preferencesDataStore */
class MainActivity : ComponentActivity() {
private lateinit var settingsRepository: SettingsRepository
// Here we instantiate our ViewModel leveraging delegates and
// a trailing lambda
private val settingsViewModel by viewModels<SettingsViewModel> {
SettingsViewModelFactory(
settingsRepository
)
}
/* onCreate -> setContent -> etc */
}
其他解决方案可行,但您必须为每个 ViewModel 创建一个工厂,这似乎有点过分了。
比较通用的方案是这样的:
inline fun <VM : ViewModel> viewModelFactory(crossinline f: () -> VM) =
object : ViewModelProvider.Factory {
override fun <T : ViewModel> create(aClass: Class<T>):T = f() as T
}
并像这样使用它:
@Composable
fun MainScreen() {
val viewModel: MyViewModel = viewModel(factory = viewModelFactory {
MyViewModel("Test Name")
})
}
对于这样的 ViewModel:
class MyViewModel(
val name: String
):ViewModel() {}