jetpack compose 将参数传递给 viewModel

Posted

技术标签:

【中文标题】jetpack compose 将参数传递给 viewModel【英文标题】:jetpack compose pass parameter to viewModel 【发布时间】:2021-08-31 01:36:21 【问题描述】:

我们如何在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.
    

【问题讨论】:

【参考方案1】:

您需要创建一个工厂来将动态参数传递给 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 网站上记录? 这实际上很难找到。如果您使用DataStore Preferences 代码实验室,其中有两个,其中一个(Working with Preferences DataStorenot Preferences DataStore ) 有一个最终解决方案,它确实利用此实现将UserRespository 类与ViewModel 绑定,但codelab 本身并没有教你任何关于它的内容并且充满差异(codelab 不是回购)。我想我们应该从 Android View 方面了解这一点,因为它在 View 系统中强烈建议始终使用 ViewModelProvider 来管理 ViewModel 实例。【参考方案2】:

通常情况下,您不需要这样做。在 android MVVM 中,视图模型通过依赖注入从存储库中获取数据。

这里是推荐的android架构的官方文档:https://developer.android.com/jetpack/guide#recommended-app-arch

【讨论】:

这实际上很棒,但我认为这对于任何小型应用程序来说也是一种过载。我相信做这个问题的一个常见案例是任何小型应用程序。我认为它只会使初学者从大量的理解中抽象出来,从而使他们免于理解如何管理一小组依赖项等。但是,我确实 100% 同意这是任何中等规模的方法应用程序,或者当您决定自己在用于任何事情的一体式模板中实现此架构时;在这种情况下也适用于小型应用程序。【参考方案3】:

正如@Secret Keeper 所说,您需要创建工厂。

如果您的 ViewModel 有依赖项, viewModel() 需要一个可选的 ViewModelProvider.Factory 作为参数。

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,您将传递可选参数。在您的 Composable 中,您可以执行以下操作。

val viewModel: MyViewModel = viewModel(
factory = MyViewModelFactory(
    dbname = "myDbName"
)

【讨论】:

【参考方案4】:

这里有一些 Jetpack Compose/Kotlin 特定的语法来实现相同的:

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 */

【讨论】:

以上是关于jetpack compose 将参数传递给 viewModel的主要内容,如果未能解决你的问题,请参考以下文章

Kotlin jetpack compose Tab的渲染 AnimatedVisibility的使用

jetpack compose 接收返回参数

如何将 POST 参数传递给 Durable Function,然后将此参数传递给 Timer Triggered 函数

未解决的参考:使用自定义 Parcelable 参数时:Jetpack Navigation

如何将参数传递给 Java 线程?

如何将参数传递给进程