簡體   English   中英

Jetpack Compose 將參數傳遞給 viewModel

[英]Jetpack Compose pass parameter to viewModel

我們如何在Jetpack Compose中將參數傳遞給viewModel

這是我的可組合

    @Composable
    fun UsersList() {
      val myViewModel: MyViewModel = viewModel("db2name") // pass param like this
    }

這是viewModel

    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

其他解決方案有效,但您必須為每個 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() {}

正如@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"
)

這是一些 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 */
}

如果你使用 Hilt,你可以在SavedStateHandle中免費獲得這個查看 model。

將參數傳遞給調用視圖 model 的可組合對象,並從保存的 state 句柄中檢索具有相同名稱的視圖 model 上的參數。

像這樣:

在 NavHost 上:

NavHost(
(...)
    composable(
            route = [route string like this $[route]/{$[argument name]}],
            arguments = listOf(
                navArgument([argument name]) { type = NavType.[type: Int/String/Boolean/etc.] }
            )
        ) {
            [Your composable]()
        }
    )
)

查看 model:

class ViewModel @Inject constructor(savedStateHandle: SavedStateHandle) {

    private val argument = checkNotNull(savedStateHandle.get<[type]>([argument name]))
}

您的論點將神奇地出現而無需查看 model 工廠。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM