Ui 未从 viewmodel kotlin flow 更新

发布于 2025-01-12 08:16:10 字数 1569 浏览 0 评论 0原文

我对 Android Flow 和 JetPack compose 很陌生,

我试图在更改可变状态时更新我的​​ UI,但这并没有调用我们的可组合项,这是我的代码

    @Composable
    fun Grid() {
        val mainViewModel by viewModels<DashBoardViewModel>()
        mainViewModel.getData()
        when (val result = mainViewModel.mutableState.value) {
            is Resource.Success -> {
                LazyVerticalGrid(
                    cells = GridCells.Adaptive(100.dp)
                ) {
                    items(result.device.items.first().devices.count()) {
                        EachItem(it)
                    }
                }
            }
            is Resource.Error -> { Text(text = result.message) }
            Resource.Loading -> { CircularProgressIndicator() }
            Resource.Empty -> {}
            else -> { CircularProgressIndicator() }
        }
    }

ViewModel:

@HiltViewModel
class DashBoardViewModel @Inject constructor(
    private val dashBoardRepository: DashBoardRepository
) : ViewModel() {

   
    val mutableState = MutableLiveData<Resource>()

    fun getData() = viewModelScope.launch {

        flow {
            emit(Resource.Loading)
            try {
               val mResponse = dashBoardRepository.getDevice()
                emit(Resource.Success(mResponse))
            } catch (e: Exception) {
                e.printStackTrace()
                emit(Resource.Error("Error"))
            }
        }.flowOn(Dispatchers.IO).collect {
            mutableState.value = it
        }
    }
}

I am quite new in Android Flow and JetPack compose,

I am trying to update my UI when mutable state is being changed , but this is not calling our composable , here is my code

    @Composable
    fun Grid() {
        val mainViewModel by viewModels<DashBoardViewModel>()
        mainViewModel.getData()
        when (val result = mainViewModel.mutableState.value) {
            is Resource.Success -> {
                LazyVerticalGrid(
                    cells = GridCells.Adaptive(100.dp)
                ) {
                    items(result.device.items.first().devices.count()) {
                        EachItem(it)
                    }
                }
            }
            is Resource.Error -> { Text(text = result.message) }
            Resource.Loading -> { CircularProgressIndicator() }
            Resource.Empty -> {}
            else -> { CircularProgressIndicator() }
        }
    }

ViewModel:

@HiltViewModel
class DashBoardViewModel @Inject constructor(
    private val dashBoardRepository: DashBoardRepository
) : ViewModel() {

   
    val mutableState = MutableLiveData<Resource>()

    fun getData() = viewModelScope.launch {

        flow {
            emit(Resource.Loading)
            try {
               val mResponse = dashBoardRepository.getDevice()
                emit(Resource.Success(mResponse))
            } catch (e: Exception) {
                e.printStackTrace()
                emit(Resource.Error("Error"))
            }
        }.flowOn(Dispatchers.IO).collect {
            mutableState.value = it
        }
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

自找没趣 2025-01-19 08:16:10

您的代码中有两个问题:

  • mainViewModel.mutableState.value 仅从可变状态获取当前值。当该值更改时,您的可组合项不会收到通知,因此它无法反映更改。如果您想在视图模型中使用 LiveData,则必须使用 observeAsState() 扩展函数,将 LivaData 转换为可自动观察的 State可组合的 功能。另一种选择是直接在视图模型中使用 (Mutable)State 。请参阅状态说明。
  • 每次 Grid() 函数重组时,即每次 mainViewModel.mutableState 更改时,都会调用您的 mainViewModel.getData() 函数(一旦你正确观察)。你绝对不希望这样。更好的解决方案是从 viewModel 的 init 块中调用 getData() ,或者,如果您确实需要从可组合函数中调用它,请使用 LaunchedEffect

而且,作为旁注,您创建流然后将其收集到 LiveData 中的方式确实很奇怪而且没有必要。你可以这样做:

fun getData() = viewModelScope.launch {
    mutableState.value = Resource.Loading
    try {
        val mResponse = dashBoardRepository.getDevice()
        mutableState.value = Resource.Success(mResponse)
    } catch (e: Exception) {
        e.printStackTrace()
        mutableState.value = Resource.Error("Error")
    }
}

There are two problems in your code:

  • mainViewModel.mutableState.value gets only the current value from your mutable state. Your composable will not be notified when this value changes and thus it cannot reflect the change. If you want to use LiveData in your viewmodel, you have to use observeAsState() extension function which converts LivaData to State that can be automatically observed by composable function. Other option is to have (Mutable)State directly in your viewmodel. See this state explanation.
  • Your mainViewModel.getData() function will be called every time your Grid() function recomposes, which will be every time your mainViewModel.mutableState changes (once you observe it correctly). You definitely don't want that. Better solution would be to call getData() from your viewModel's init block, or, if you really need to call it from your composable function, use LaunchedEffect.

And, as a side note, the way you are creating flow and then collecting it into LiveData is really odd and unnecessary. You can do something like this instead:

fun getData() = viewModelScope.launch {
    mutableState.value = Resource.Loading
    try {
        val mResponse = dashBoardRepository.getDevice()
        mutableState.value = Resource.Success(mResponse)
    } catch (e: Exception) {
        e.printStackTrace()
        mutableState.value = Resource.Error("Error")
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文