如何在依赖于视图模型的可组合函数中进行预览?

2023-12-30

问题描述

我想要预览我的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)
    ...

My code

这是我的HomeScreen code:

@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 = {})
}

我的视图模型:

@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
}

我失败的尝试

我认为这可能是视图模型作为我的默认参数传递的问题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带有模拟视图模型。


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

@Preview
@Composable
private fun HomeScreenPreview() {
    val viewModel = HomeViewModel()
    // setup viewModel as you need it to be in the preview
    HomeScreen(viewModel = viewModel, navigateToDetailsAction = {}, openCardDetailsAction = {})
}

由于您有一个存储库,因此您可以执行与测试视图模型相同的操作。

  1. 创建接口用​​于CityRepository
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)
}
  1. 实施它是为了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)
}
  1. Create 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 }
}

所以你可以将它传递到你的视图模型中:HomeViewModel(FakeCityRepository())

你可以用同样的方法AppDatabase而不是存储库,这完全取决于您的需求。查看更多有关刀柄测试 https://developer.android.com/training/dependency-injection/hilt-testing

附注我不确定这是否会建立,因为我没有你的一些课程,但你应该已经明白了这个想法。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在依赖于视图模型的可组合函数中进行预览? 的相关文章

  • Android Studio 3.0 Canary 9 - 无法解析包

    我在 Android Studio 3 0 Canary 9 中遇到几个错误 这些错误是 无法解析 android 软件包 下面列出了一些错误 我刚刚安装了 SDK 的所有额外软件包 但仍然收到 gradle 构建错误 Error 82 1
  • 使用workmanager时Firestore脱机持久性错误

    我正在使用一个WorkManger定期从我的中检索信息Firestore当应用程序处于后台和前台时的数据库 此信息用于根据状态更新 UI 因此不同的状态会添加或删除 UI 的不同部分 第一次运行时效果很好 但是 一旦应用程序处于后台并且Wo
  • React Native 从 JavaScript 代码内部访问 strings.xml

    有没有办法访问当前值android app src main res values strings xml从 JavaScript 代码内部 我想为每个构建放置不同的端点 URL 但我什至无法检测到反应本机代码内的构建类型 而不必求助于 D
  • Sqlite数据库生命周期?关闭应用程序后它会被删除吗?

    我正在遵循一个简单的教程 该教程创建一个从 SQLiteOpenHelper 扩展的类 并创建一个包含一个表和 5 行的数据库 好的 但我需要更多地了解 android Sqlite 数据库 例如 如果应用程序关闭或手机关机会发生什么 数据
  • Android 后退按钮无法与 Flutter 选项卡内的导航器配合使用

    我需要在每个选项卡内有一个导航器 因此当我推送新的小部件时 选项卡栏会保留在屏幕上 代码运行得很好 但是 android 后退按钮正在关闭应用程序而不是运行 Navigator pop import package flutter mate
  • java.lang.NoClassDefFoundError:org.apache.batik.dom.svg.SVGDOMImplementation

    我在链接到我的 Android LibGDX 项目的 Apache Batik 库时遇到了奇怪的问题 但让我们从头开始 在 IntelliJ Idea 中我有一个项目 其中包含三个模块 Main Android 和 Desktop 我强调的
  • Android 模拟器插件无法初始化后端 EGL 显示

    我在 Cloudbees 上设置了 Jenkins 作业 并且可以在那里成功签出并编译我的 Android 项目 现在我想在 android 模拟器中运行一些 JUnit 测试并添加 Android 模拟器插件 我将 显示模拟器窗口 选项设
  • CollapsingToolBarLayout - 状态栏稀松布颜色不改变

    几天前我更新了我的 android studio 并开始使用 CoordinatorLayout 和 CollapsingToolbarLayout 只是尝试一些东西 工具栏稀松布颜色似乎覆盖了状态栏初始颜色和状态栏稀松布颜色 从 xml
  • 是否必须删除 Intent extra?

    这可能是一个愚蠢的问题 但是是否有一条规则规定消费活动必须显式删除 Intent 额外内容 或者只有在回收 Intent 对象时才如此 换句话说 如果我总是通过执行以下操作来链接到下一个活动 Intent i new Intent MyCu
  • 在 HTTPResponse Android 中跟踪重定向

    我需要遵循 HTTPost 给我的重定向 当我发出 HTTP post 并尝试读取响应时 我得到重定向页面 html 我怎样才能解决这个问题 代码 public void parseDoc final HttpParams params n
  • 如何使用 Cordova 获取当前安装的应用程序的版本?

    我已经找到了应用程序可用性插件 https github com ohh2ahh AppAvailability它主要检查用户是否在其设备上安装了某个应用程序 是否有可能获得应用程序的当前版本 开发者名称 重要 以及所有可能的信息 一般来说
  • 你的CPU不支持NX

    我刚刚下载了 android studio 但是我遇到了一个问题 当我运行它时 它说你的 cpu 不支持 NX 我应该怎么办 NX 或实际上是 NX 处理器位 是处理器的一项功能 有助于保护您的 PC 免受恶意软件的攻击 当此功能未启用并且
  • 如何在PreferenceActivity中添加工具栏

    我已经使用首选项创建了应用程序设置 但我注意到 我的 PreferenceActivity 中没有工具栏 如何将工具栏添加到我的 PreferenceActivity 中 My code 我的 pref xml
  • 如何使用 IF 检查 TextView 可见性

    我有一个 onCheckedChangeListener 来根据选择的单选按钮显示文本视图 我有 1 个疑问和 1 个难题 想知道是否有人可以帮助我 问题 您能否将单选组默认检查值设置为 否 单选按钮 以便一开始就不会检查任何内容 问题 如
  • 在 android DatePickerDialog 中将语言设置为法语

    有什么办法可以让日期显示在DatePickerDialog用法语 我已经搜索过这个但没有找到结果 这是我的代码 Calendar c Calendar getInstance picker new DatePickerDialog Paym
  • 字符串数组文本格式化

    我有这个字符串 String text Address 1 Street nr 45 Address 2 Street nr 67 Address 3 Street nr 56 n Phone number 000000000 稍后将被使用
  • 如何根据 gradle 风格设置变量

    我想传递一个变量test我为每种风格设置了不同的值作为 NDK 的定义 但出于某种原因 他总是忽略了最后味道的价值 这是 build gradle apply plugin com android library def test andr
  • 如何确定对手机号码的呼叫是本地呼叫还是 STD 或 ISD

    我正在为 Android 开发某种应用程序 但不知道如何获取被叫号码是本地或 STD 的号码的数据 即手机号码检查器等应用程序从哪里获取数据 注意 我说的是手机号码 而不是固定电话 固定电话号码 你得到的数字是字符串类型 因此 您可以获取号
  • 将 Intent 包装在 LabeledIntent 中以用于显示目的

    要求 我的应用程序中有一个 共享 按钮 我需要通过 Facebook 分享 我需要选择是否安装原生 Facebook 应用程序 我们的决定是 如果未安装该应用程序 则将用户发送到 facebook com 进行分享 当前状态 我可以检测何时
  • 节拍匹配算法

    我最近开始尝试创建一个移动应用程序 iOS Android 它将自动击败比赛 http en wikipedia org wiki Beatmatching http en wikipedia org wiki Beatmatching 两

随机推荐

  • Stacktrace 不打印在 Glassfish 4.1 集群日志中

    在 Glassfish 4 1 上进行第一个集群设置 应用程序 EAR 级别日志 例如打印堆栈跟踪 似乎无法到达 GF dir domains logs server log 或 GF dir nodes node name 中的服务器 实
  • 如何防止 MATLAB 中的填充命令创建没有“角”的框

    我目前正在 MATLAB 中使用 fill 命令来创建使用 fill 命令创建的框图形 实际代码基于这个 StackOverflow 问题 https stackoverflow com questions 15008705 how to
  • 可以使用antixml创建xml文档吗?

    有一些使用 Anti Xml 从 XML 文档中提取信息的示例 但我找不到使用 Anti Xml 创建 XML 文档的示例 Anti Xml 是否支持创建文档 或者我应该为此使用另一个库 哪个 有人有使用 Anti Xml 创建 XML 文
  • 在 setTimeout() 中使用 $(this) ;

    我想在 jQuery 中动态设置超时 动态设置超时函数需要使用 this 但我似乎无法让它工作 一个例子 div each function var content this attr data content setTimeout thi
  • 输入字段禁用,直到选中单选按钮 (HTML)

    我有两个字段 其中一个是文本输入字段 另一个是选择标签 问题是我只想启用其中之一 用户应通过单击上面的单选按钮之一来选择启用哪一项 因此 如果用户选择第一个单选按钮 输入字段将被启用 如果他选择第二个 则选择标签将被启用 这是我的代码
  • python 中是否有相当于 Ruby 的“rvm”的工具?

    Q Python 中是否有与Ruby 版本管理器 rvm http rvm beginrescueend com workflow rvmrc RVM让你轻松切换完全地不同版本的 Ruby 解释器之间and不同的宝石 模块 集 与解释器和
  • 模仿否定后向查找以匹配 JavaScript 正则表达式中未紧随其后的特定字符的模式

    我在 Javascript 中有这个正则表达式 0x A F0 9 2 g 我想修改它 以便在前一个字符不是时获得匹配 像这样的东西 0x60 gt 正确 0x60 gt 假 我想出了类似的东西 但它不能正常工作 0x A F0 9 2 g
  • 升级期间在 Android Market 中重命名应用程序

    我想在下次升级期间重命名我发布的应用程序 Android Market 是否会将其视为另一次常规升级并保留相关的评级和评论 该应用程序将保留相同的包名称 只要包名称相同 保留什么应用程序名称并不重要 我经常切换我的应用程序标题 在市场中 以
  • 在 DevExpress CheckedComboBox 中获取选中的项目

    我正在使用DevExpress 9 3 CheckedComboBoxEdit 我需要获取所有选中项目的集合 看起来这应该是一个简单的任务 但我发现的最接近解决方案的是我可以使用 CheckedComboBoxEdit Properties
  • 用java生成AutoCAD文件?

    有谁知道如何使用 Java 生成 AutoCAD 绘图吗 dfx 是一个好的界面还是我们应该使用 dwg 文件 我在网上找不到任何关于此的有用信息 开放设计联盟有用于生成 dwg 的库 但如果不成为会员 我就无法查看 API 而且他们似乎也
  • 为什么调用函数时需要“抛出异常”?

    class throwseg1 void show throws Exception throw new Exception my own Exception void show2 throws Exception Why throws i
  • 如何在按确定后停止显示 javascript 警报

    我想在 Facebook 收件箱中有内容时显示提醒 我认为使用用户脚本可以轻松完成 这就是我到目前为止所拥有的 感谢用户脚本 http userscripts org forums论坛 document addEventListener D
  • 在 VB.net 中获取 shell 命令的输出

    我有一个 VB net 程序 在其中调用 Shell 函数 我想在文件中获取从此代码生成的文本输出 但是 这不是执行代码的返回值 所以我真的不知道该怎么做 该程序是一项服务 但可以毫无问题地访问磁盘 因为我已经记录了其他信息 整个服务有多个
  • 如何在 Xcode 9 Playground 中使用 Swift 包管理器 [重复]

    这个问题在这里已经有答案了 是否可以在 Xcode 9 Playground 中使用 Swift Package Manager 目前无法在 Playground 中使用 Swift Package Manager 原因是 Swift 包管
  • Windows 窗体保存到 XML

    我有一个表单 其中包含用户输入的信息 我想将其保存为 XML 我对编程相当陌生 但已经阅读过 XML 是最好的使用方法 我该怎么办呢 如果有帮助的话我可以使用 Sharp Develop 作为 IDE 目前它有 10 个文本框和 10 个日
  • 向函数传递超过 255 个参数

    我只是简单地传递我的论点def声明给def陈述 我不知道您可以通过的参数数量有限制 我假设参数是变量 我需要能够通过超过 255 个参数 有人可以用外行术语帮助我如何解决 超过 255 个参数 谢谢 Code def a Things ha
  • 命名 ant 目标的最佳实践是什么?

    命名 ant 目标的最佳实践是什么 例如 您希望目标 测试 运行什么 所有单元测试 所有功能测试 两个都 用于运行不同类型测试 单元 功能 全部 的标准名称是什么 在 J2SE 中部署软件的目标名称是否有标准 在J2EE 中 我的项目将 a
  • 如何使 tkinter 文本小部件不可选择?

    我想做我的 tkinterText仅作为输出而不是输入 通过一些研究我发现text config state disabled 禁用用户输入 但它仍然允许选择我不想要的文本 我怎样才能得到我的Text小部件不可选择且不可写 最简单的方法是替
  • Android ArrayAdapter 过滤问题

    因为我想使用自定义列表适配器 以便我可以设置列表样式 但过滤器功能不起作用 我可以进行基本过滤 但是一旦过滤结果列表少于我开始过滤时显示的 listItems 数量 应用程序就会崩溃 这段代码中还有第二个问题 我不确定它是否相关 但是当cl
  • 如何在依赖于视图模型的可组合函数中进行预览?

    问题描述 我想要预览我的HomeScreen我的可组合函数HomeScreenPrevieiw预览功能 但是这是不可能的 因为我收到以下错误 java lang IllegalStateException ViewModels creati