android 试图找到一种方法让我的viewmodel在撰写预览

izkcnapc  于 2023-04-28  发布在  Android
关注(0)|答案(1)|浏览(135)

我对jetpack compose还是个新手,我一直在尝试设置预览以使开发更容易,但我找不到一种方法来使用ViewModelProvider或在预览上下文中获取应用程序。
我的TimeViewModel需要将Application作为参数传入...

class TimeViewModel(appObj: Application): AndroidViewModel(appObj) {...

然后在我的MainActivity中,我像这样创建它...

val timeViewModel = ViewModelProvider(this)[TimeViewModel::class.java]

然后将其传递给任何可能需要它的可组合对象。特别是我的ProgressView。
我希望能够预览我的ProgressView,但我不能,因为它需要timeViewModel作为参数传递给它。
在我的主要活动中,它很简单...

ProgressView(timeViewModel)

但是在@Preview中我不能示例化TimeViewModel
我试过这么做...

@Preview
@Composable
fun PreviewProgress() {
  val timeViewModel = TimeViewModel(LocalContext.current as Application)
  ProgressView(model = timeViewModel)
}

但我一直得到一个渲染问题,点击它显示我...
java.lang.ClassCastException: class com.android.layoutlib.bridge.android.BridgeContext cannot be cast to class android.app.Application
我不能使用ViewModelProvider(this)[TimeViewModel::class.java]的相同方法,因为this在预览上下文中不存在。我也尝试使用相同的LocalContext.current as Application,但也不起作用。
我试过谷歌搜索,但找不到任何帮助。有没有办法在@Preview中使用ViewModelProvider?
我还应该提到TimeViewModel是一个Room数据库。android wear-os-samples git hub,我相信code-lab,显示视图模型传递给应用程序,以便在其中创建repo。

mzillmmw

mzillmmw1#

在视图模型上有任何UI的上下文都是不好的,因为视图模型应该只处理状态。
但是,如果您想保持代码的这种方式,您可以使用MVI设计模式。
使用MVI,UI将仅发送事件(actions)到视图模型,视图模型将负责执行任务,必要时调用任何方法。UI将只从视图模型接收状态并随其更改。这样,很容易将视图模型与屏幕分离。您必须有一个可组合的内容,只接收状态模型和回调发送您的事件(动作)可以预览此内容组合。现在很容易模拟此值。
这是一个如何在Jetpack Compose中使用MVI模式的例子。

TimeViewState.kt

data class TimeViewState(
   val name: String = "",
   val error: Throwable? = null
)

TimeViewEvent.kt

sealed class TimeViewEvent {
    object Set {
        data class Name(val value: String): TimeViewEvent()
        data class Error(val value: Throwable?): TimeViewEvent()
    }
}

TimeViewModel.kt

class TimeViewModel(appObj: Application): AndroidViewModel(appObj) {
    private val _state = MutableStateFlow(TimeViewState())
    val state = _uiState.asStateFlow()

    fun dispatchEvent(event: TimeViewEvent) {
        when (event) {
            is TimeViewEvent.Set.Name -> setName(event.value)
            is TimeViewEvent.Set.Error -> setError(event.value)
        }
    }

    private fun setName(value: String) {
        _state.update { it.copy(name = value) }
    }

    private fun setError(value: Throwable?) {
        _state.update { it.copy(error = value) }
    }
}

ProgressView.kt

@Composable
fun ProgressView(viewModel: TimeViewModel) {
    val state by viewModel.state.collectAsState()

    Content(
        state = state,
        event = viewModel::dispatchEvent
    )
}

@Composable
private fun Content(
    state: TimeViewState,
    event: (TimeViewAction) -> Unit
) {
   // your ui here
}

@Preview
@Composable
private fun ContentPreview() {
    Content(TimeViewState()) {}
}

相关问题