gpt4 book ai didi

android - 如何在依赖于 View 模型的可组合函数中获得预览?

转载 作者:行者123 更新时间:2023-12-04 14:51:07 26 4
gpt4 key购买 nike

问题描述
我想预览我的HomeScreen我的 HomeScreenPrevieiw 中的可组合函数预览功能。但是,这是不可能的,因为我收到以下错误:

java.lang.IllegalStateException: ViewModels creation is not supported in Preview
at androidx.compose.ui.tooling.ComposeViewAdapter$FakeViewModelStoreOwner$1.getViewModelStore(ComposeViewAdapter.kt:709)
at androidx.lifecycle.ViewModelProvider.<init>(ViewModelProvider.kt:105)
at androidx.lifecycle.viewmodel.compose.ViewModelKt.get(ViewModel.kt:82)
at androidx.lifecycle.viewmodel.compose.ViewModelKt.viewModel(ViewModel.kt:72)
at com.example.crud.ui.screens.home.HomeScreenKt.HomeScreen(HomeScreen.kt:53)
at com.example.crud.ui.screens.home.HomeScreenKt.HomeScreenPreview(HomeScreen.kt:43)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
...
我的代码
这是我的 HomeScreen代码:
@Composable
fun HomeScreen(
viewModel: HomeViewModel = hiltViewModel(),
navigateToDetailsAction: () -> Unit,
openCardDetailsAction: (Int) -> Unit
) {
val cities = viewModel.cities.observeAsState(listOf())
Scaffold(
topBar = { HomeAppBar() },
floatingActionButton = { HomeFab(navigateToDetailsAction) }
) {
HomeContent(cities) { id -> openCardDetailsAction(id) }
}
}
这是我的预览功能的代码:
@Preview
@Composable
private fun HomeScreenPreview() {
HomeScreen(navigateToDetailsAction = {}, openCardDetailsAction = {})
}
我的 View 模型:
@HiltViewModel
class HomeViewModel @Inject constructor(repository: CityRepository) : ViewModel() {
val cities: LiveData<List<City>> = repository.allCities.asLiveData()
}
存储库:
@ViewModelScoped
class CityRepository @Inject constructor(appDatabase: AppDatabase) {
private val dao by lazy { appDatabase.getCityDao() }

val allCities by lazy { dao.getAllCities() }

suspend fun addCity(city: City) = dao.insert(city)

suspend fun updateCity(city: City) = dao.update(city)

suspend fun deleteCity(city: City) = dao.delete(city)

suspend fun getCityById(id: Int) = dao.getCityById(id)

}
应用数据库:
@Database(entities = [City::class], version = 2, exportSchema = false)
abstract class AppDatabase : RoomDatabase() {
abstract fun getCityDao() : CityDao
}
我失败的尝试
我认为这可能是 View 模型作为我的 HomeScreen 的默认参数传递的问题。所以我决定这样做:
@Composable
fun HomeScreen(
navigateToDetailsAction: () -> Unit,
openCardDetailsAction: (Int) -> Unit
) {
val viewModel: HomeViewModel = hiltViewModel()
val cities = viewModel.cities.observeAsState(listOf())
Scaffold(
topBar = { HomeAppBar() },
floatingActionButton = { HomeFab(navigateToDetailsAction) }
) {
HomeContent(cities) { id -> openCardDetailsAction(id) }
}
}
但它仍然不起作用(我不断收到同样的错误),而且它不适合测试,因为它会阻止我测试我的 HomeScreen使用模拟 View 模型。

最佳答案

这正是使用默认值传递 View 模型的原因之一。在预览中,您可以传递一个测试对象:

@Preview
@Composable
private fun HomeScreenPreview() {
val viewModel = HomeViewModel()
// setup viewModel as you need it to be in the preview
HomeScreen(viewModel = viewModel, navigateToDetailsAction = {}, openCardDetailsAction = {})
}
由于您有一个存储库,因此您可以执行与测试 View 模型相同的操作。
  • CityRepository 创建接口(interface)
  • interface CityRepositoryI {
    val allCities: List<City>

    suspend fun addCity(city: City)
    suspend fun updateCity(city: City)
    suspend fun deleteCity(city: City)
    suspend fun getCityById(id: Int)
    }
  • CityRepository 实现它:
  • @ViewModelScoped
    class CityRepository @Inject constructor(appDatabase: AppDatabase) : CityRepositoryI {
    private val dao by lazy { appDatabase.getCityDao() }

    override val allCities by lazy { dao.getAllCities() }

    override suspend fun addCity(city: City) = dao.insert(city)

    override suspend fun updateCity(city: City) = dao.update(city)

    override suspend fun deleteCity(city: City) = dao.delete(city)

    override suspend fun getCityById(id: Int) = dao.getCityById(id)
    }
  • 创建 FakeCityRepository用于测试目的:
  • class FakeCityRepository : CityRepositoryI {
    // predefined cities for testing
    val cities = listOf(
    City(1)
    ).toMutableStateList()

    override val allCities by lazy { cities }

    override suspend fun addCity(city: City) {
    cities.add(city)
    }

    override suspend fun updateCity(city: City){
    val index = cities.indexOfFirst { it.id == city.id }
    cities[index] = city
    }

    override suspend fun deleteCity(city: City) {
    cities.removeAll { it.id == city.id }
    }

    override suspend fun getCityById(id: Int) = cities.first { it.id == id }
    }
    所以你可以将它传递到你的 View 模型中: HomeViewModel(FakeCityRepository())你可以用 AppDatabase 做同样的事情而不是存储库,这完全取决于您的需求。查看更多关于 Hilt testing 的信息
    p.s.我不确定这是否会建立,因为我没有你的一些类(class),但你应该已经明白了。

    关于android - 如何在依赖于 View 模型的可组合函数中获得预览?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69089816/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com