标签: viewmodel-savedstate

ViewModel中的SavedStateHandle和currentBackStackEntry是否相同?

我想使用 saveStateHandle 将一些数据从活动直接传递到片段的视图模型。

在我的活动中我有:

navController.addOnDestinationChangedListener { controller, _, _ ->
    controller.currentBackStackEntry?.savedStateHandle?.set(
        "foo",
         "bar"
    )
}
Run Code Online (Sandbox Code Playgroud)

所以viewModel中的代码如下所示:

MyViewModel(state: SavedStateHandle) : ViewModel() {

    init {
        state
            ?.getStateFlow("foo", "")
            ?.onEach { /* do something */ }
            ?.launchIn(viewModelScope)
    }

Run Code Online (Sandbox Code Playgroud)

由于某种原因,期望值bar永远不会被发出。

我已经检查了Fragment本身,数据就在那里:

val handle = findNavController().currentBackStackEntry?.savedStateHandle

handle?.getLiveData<String>("foo")?.observe(viewLifecycleOwner) {
    // here it is

}
Run Code Online (Sandbox Code Playgroud)

但是是否有可能将数据直接传递到 viewModel 的 savingStateHandle ?我相信应该是这样,因为导航器以某种方式通过了。

android android-savedstate android-viewmodel android-jetpack-navigation viewmodel-savedstate

10
推荐指数
0
解决办法
558
查看次数

如何从 AbstractSavedStateViewModelFactory 动态设置包

我的视图模型工厂

class ViewModelFactory @Inject constructor(
    private val viewModelMap: MutableMap<Class<out ViewModel>, ViewModelAssistedFactory<out ViewModel>>,
    owner: SavedStateRegistryOwner,
    defaultArgs: Bundle?
) : AbstractSavedStateViewModelFactory(owner, defaultArgs) {

    @Throws(IllegalStateException::class)
    @Suppress("UNCHECKED_CAST")
    override fun <T : ViewModel?> create(key: String, modelClass: Class<T>, handle: SavedStateHandle): T {
        return viewModelMap[modelClass]?.create(handle) as? T ?: throw IllegalStateException("Unknown ViewModel class")
    }
}
Run Code Online (Sandbox Code Playgroud)

活动

@Inject
lateinit var viewModelFactory: ViewModelFactory
protected val viewModel: ViewModel by lazy { ViewModelProvider(this, viewModelFactory).get(getViewModelClass()) }
Run Code Online (Sandbox Code Playgroud)

视图模型

@AssistedInject.Factory
interface Factory : ViewModelAssistedFactory<SplashViewModel>
Run Code Online (Sandbox Code Playgroud)

我想知道如何动态提供 defaultArgs 而不是:

活动模块

@Module
    companion object …
Run Code Online (Sandbox Code Playgroud)

android android-lifecycle dagger-2 android-viewmodel viewmodel-savedstate

7
推荐指数
1
解决办法
2196
查看次数

io.mockk.MockKException:找不到答案:SavedStateHandle(#1).set(Key,Something)

我有一个 ViewModel 类如下(简化以演示我面临的问题)

class MyViewModel(private val savedStateHandle: SavedStateHandle) : ViewModel() {
    init {
        savedStateHandle.set(KEY, "Something")
    }
}
Run Code Online (Sandbox Code Playgroud)

我有一个 MockK 测试类,如下所示

@Test
fun `test something simple`() {
    val savedStateHandle = mockk<SavedStateHandle>()
    val viewModel = MyViewModel(savedStateHandle)
    verify { savedStateHandle.set(MyViewModel.KEY, "Something") }
}
Run Code Online (Sandbox Code Playgroud)

通过运行测试,我得到以下错误

io.mockk.MockKException: no answer found for: SavedStateHandle(#1).set(Key, Something)
Run Code Online (Sandbox Code Playgroud)

我想我也需要处理setfor SavedStateHandle。我怎么能这样做MockK呢?

kotlin mockk viewmodel-savedstate

6
推荐指数
1
解决办法
5067
查看次数

如何延迟保存ViewModel的SavedStateHandle?

我有一个屏幕,可以加载一堆请求并从同一屏幕上的用户和外部 WebView 收集一些数据。因此,我有一个包含这些复杂请求对象(+用户输入数据)的 ViewModel。我需要通过系统启动的进程死亡来持久保存这些数据,这SavedStateHandle是设计的目的。但我不想将这些数据保留在数据库中,因为它只与当前的用户体验相关。

我已将我的 ViewModel 与 Hilt 集成并收到了SaveStateHandle. 因为我有一些复杂的对象,可以在代码中的多个位置访问/修改它们,所以我无法“随时随地”保存它们。我让它们实现Parcelable,只是想立即保存它们。不幸的是,ViewModel 没有像onSaveInstanceState().

现在,我尝试使用onCleared()听起来像是写入句柄的好地方。但事实证明,.set()我在那里执行的所有操作都会丢失(我正在使用开发人员选项“不保留活动”进行测试。当我.set()在其他地方使用时,它确实有效)。因为 ViewModel 不依赖于单个片段/活动的生命周期,而是依赖于 NavGraph,所以我无法从它们的onSaveInstanceState().

我如何/在哪里可以正确地保留我的状态SaveStateHandle

android viewmodel android-savedstate viewmodel-savedstate

6
推荐指数
1
解决办法
3418
查看次数

尝试将 SavedStateHandle.getLiveData() 公开为 MutableStateFlow,但 UI 线程冻结

我正在尝试使用以下代码:

suspend fun <T> SavedStateHandle.getStateFlow(
    key: String,
    initialValue: T? = get(key)
): MutableStateFlow<T?> = this.let { handle ->
    withContext(Dispatchers.Main.immediate) {
        val liveData = handle.getLiveData<T?>(key, initialValue).also { liveData ->
            if (liveData.value === initialValue) {
                liveData.value = initialValue
            }
        }

        val mutableStateFlow = MutableStateFlow(liveData.value)

        val observer: Observer<T?> = Observer { value ->
            if (value != mutableStateFlow.value) {
                mutableStateFlow.value = value
            }
        }

        liveData.observeForever(observer)

        mutableStateFlow.also { flow ->
            flow.onCompletion {
                withContext(Dispatchers.Main.immediate) {
                    liveData.removeObserver(observer)
                }
            }.onEach { value ->
                withContext(Dispatchers.Main.immediate) {
                    if (liveData.value != …
Run Code Online (Sandbox Code Playgroud)

android kotlin android-jetpack viewmodel-savedstate kotlin-flow

5
推荐指数
2
解决办法
527
查看次数

Jetpack Compose 使用 SavedStateHandle 发送返回结果不适用于 ViewModel 中注入的 SavedStateHandle

使用 SavedStateHandle 发送回结果不适用于 ViewModel 中注入的 SavedStateHandle。

使用navController.currentBackStackEntry?.savedStateHandle?它可以得到结果!

fun CreatePostScreen(
    navController: NavController,
    coroutineScope: CoroutineScope,
    snackbarState: SnackbarHostState,
    viewModel: CreatePostViewModel = hiltViewModel(),
) {

    LaunchedEffect(key1 = Unit) {

        navController.currentBackStackEntry?.savedStateHandle?.getStateFlow(
            "result", ""
        )?.collect { result ->
            Timber.d("Result -> $result")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在 ViewModel 中使用saveStateHandleHilt 注入不会得到结果!

@HiltViewModel
class CreatePostViewModel @Inject constructor(
    private val savedStateHandle: SavedStateHandle,
) : ViewModel() {
    
    init {

        viewModelScope.launch {
            savedStateHandle.getStateFlow("result", "").collect {
                Timber.d("Result -> $it")
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这就是我将结果发送回前一屏幕的方式!

navController.previousBackStackEntry?.savedStateHandle?.set("result", "this is result")
Run Code Online (Sandbox Code Playgroud)

android android-jetpack-navigation android-jetpack-compose viewmodel-savedstate dagger-hilt

4
推荐指数
1
解决办法
1527
查看次数

SavedStateHandle不持久化数据

我按照下一页中的说明创建了一个 viewModel,但当SavedStateHandle我关闭应用程序并再次打开它时,它不起作用。

这是页面:

ViewModel 的已保存状态模块

这是我的视图模型类:

class UserViewModel(private val state : SavedStateHandle) : ViewModel(){
    val userId: LiveData<String> by lazy {
         state.getLiveData("userId")
    }
    fun setUserId(userId : String) {
        state["userId"] = userId
    }
    val user : User by lazy {
        User("")
    } }
Run Code Online (Sandbox Code Playgroud)

以下是我在活动中使用 viewModel 的方式。

val userViewModel :  UserViewModel by viewModels()
Run Code Online (Sandbox Code Playgroud)

我什至在我的活动中尝试过这个,但这也不起作用!

val userViewModel: UserViewModel by viewModels {
            SavedStateViewModelFactory(
                application,
                this
            )
Run Code Online (Sandbox Code Playgroud)

我应该怎么做才能将数据持久化SavedStateHandle?我的意思是,打开应用程序后state仍然是空的。

android-savedstate android-viewmodel viewmodel-savedstate

3
推荐指数
1
解决办法
5667
查看次数

savedStateHandle 不保存状态

在这个问题之后,我在我的应用程序中做了一些简单的更改,但它没有按我的预期工作。

我有一个计时器,当计时器完成时会发送通知。单击此通知将重新启动活动,删除所有计时器信息,这些信息主要存储在viewModel. 出于这个原因,我决定使用保存的状态viewModel

这是我的viewModel

class TimerViewModel(private val savedStateHandle: SavedStateHandle) : ViewModel() {

private val _secondsRemaining = savedStateHandle.getLiveData<Long>(SECONDS_REMAINING)
val secondsRemaining : LiveData<Long>
    get() = _secondsRemaining
Run Code Online (Sandbox Code Playgroud)

viewModel这是我在我的中使用的方法Fragment

private val timerViewModel by viewModels<TimerViewModel>()
Run Code Online (Sandbox Code Playgroud)

当我启动计时器时,我会在时钟LiveData的每个滴答声中保存剩余秒数的值。当计时器结束时,应用程序发送通知,计时器再次启动,计算一个新的周期:

timer = object : CountDownTimer(timerLengthSeconds * 1000, 1000){
        override fun onFinish(){
            (....)
        }

        override fun onTick(millisUntilFinished: Long) {
            var secondsRemainingInCountdown = millisUntilFinished / 1000

            (...)

            _secondsRemaining.value = secondsRemainingInCountdown
         
        }
    }.start()
}
Run Code Online (Sandbox Code Playgroud)

因此,当计时器完成时,应用程序会发送通知,但计时器已重新启动,并且剩余的秒数正在更新(我已通过日志检查了这一点)。当用户单击通知时,通知会activity被终止并重新启动,并且期望会看到计时器以及保存在LiveData. 但是当 …

android persistence viewmodel kotlin viewmodel-savedstate

3
推荐指数
1
解决办法
4029
查看次数