我可以在 MutableLiveData 上使用observerAsState()吗?

问题描述 投票:0回答:1

我在构建小型电影库应用程序时遇到了问题。我的结构如下:我有一个 MovieSearchScreen 函数,它调用 SearchBar 函数以及 MovieSearchResults 函数。在 Searchbar 函数中,我有一个 TextField、一个leadingIcon 和一个 TrailingIcon,其中有一个可点击的修饰符,该修饰符调用我的 viewModel 中的 updateMovieResource 函数:

    @Composable
    fun Create(navController: NavHostController, viewModel: MovieViewModel) {
        Column(
            modifier = Modifier
                .fillMaxSize()
                .background(color = Color.DarkGray)
        ) {
            SearchBar(viewModel = viewModel)
            MovieSearchResults(navController = navController)
        }
    }

    @Composable
    private fun SearchBar(viewModel: MovieViewModel) {
        var userInput: String by remember {
            mutableStateOf("")
        }
        TextField(
            value = userInput,
            onValueChange = {
                userInput = it
                            },
            modifier = Modifier
                .fillMaxWidth(),
            colors = TextFieldDefaults.colors(
                focusedContainerColor = Color.Gray,
                unfocusedContainerColor = Color.Gray,
                focusedTextColor = Color.White,
                unfocusedTextColor = Color.White
            ),
            placeholder = {
                Text(
                    text = stringResource(id = R.string.search_bar),
                    color = Color.White
                )
                          },
            leadingIcon = {
                Icon(
                    imageVector = Icons.Rounded.Clear,
                    contentDescription = "Clear",
                    modifier = Modifier
                        .clickable {
                            userInput = ""
                                   },
                    tint = Color.White
                )
                          },
            trailingIcon = {
                Icon(
                    imageVector = Icons.Rounded.Search,
                    contentDescription = "Search",
                    tint = Color.White,
                    modifier = Modifier.clickable {
                        if (userInput.isNotBlank()) {
                            viewModel.updateMovieResource(userInput)
                        }
                    }
                )
            }
        )
    }

在此 viewModel 中,我有几个值,目前重要的是我的 _movieRepository,我在其中管理 api 调用、_movieResource、movieResource 和 updateMovieResource 方法:

class MovieViewModel: ViewModel() {

    private lateinit var _selectedMovie: MutableState<Movie>

    var selectedMovie: Movie
        get() = _selectedMovie.value
        set(movie){
            _selectedMovie.value = movie
        }

    private val _movieRepository: MovieRepository = MovieRepository()

    val movieResource: LiveData<Resource<ResponseResult>>
        get() = _movieResource

    private val _movieResource: MutableLiveData<Resource<ResponseResult>> =
        MutableLiveData(Resource.Empty())

    fun updateMovieResource(movie: String) {
        _movieResource.value = Resource.Loading()

        viewModelScope.launch {
            _movieResource.value = _movieRepository.getMovie(movie)
        }
    }
}

我使用 movieResource 来确定我的 api 调用是否成功、仍在加载或返回错误,以便我知道要显示什么。我在此处的 MovieSearchResults 可组合项中使用此 movieResource:

@Composable
    private fun MovieSearchResults(
        navController: NavHostController,
        viewModel: MovieViewModel = androidx.lifecycle.viewmodel.compose.viewModel()
    ){
        val movieResource: Resource<ResponseResult>? by viewModel.movieResource.observeAsState()
        
        Column(
            modifier = Modifier.fillMaxSize(),
            horizontalAlignment = Alignment.CenterHorizontally,
            verticalArrangement = Arrangement.Center
        ) {
            when(movieResource) {
                is Resource.Success ->
                    LazyVerticalGrid(
                        columns = GridCells.Fixed(3)
                    ) {
                        items(
                            items = (movieResource as Resource.Success<ResponseResult>).data!!.results,
                            itemContent = {
                                AsyncImage(
                                    model = it.backdropPath,
                                    contentDescription = it.title,
                                    modifier = Modifier.clickable {
                                        viewModel.selectedMovie = it
                                        navController.navigate(MovieLibraryScreens.MovieDetailsScreen.name)
                                    }
                                )
                            }
                        )
                    }
                is Resource.Error ->
                    Text(
                        text = (movieResource as Resource.Error<ResponseResult>).message!!,
                        fontSize = 30.sp,
                        color = Color.Red
                    )
                is Resource.Empty ->
                    Text(
                        text = "Search for a movie!",
                        fontSize = 30.sp,
                        color = Color.White
                    )
                is Resource.Loading ->
                    Text(
                        text = "Loading...",
                        fontSize = 30.sp,
                        color = Color.White
                    )
                else ->
                    Text(
                        text = "Something went wrong...",
                        fontSize = 30.sp,
                        color = Color.White
                    )
            }
        }
    }

我从我的存储库中检索此数据:

class MovieRepository {

    private val _apiService: ApiService = Api().createApi()

    private val _apiKey: String = API_KEY

    suspend fun getMovie(movie: String): Resource<ResponseResult> {
        val response = try {
            withTimeout(5_000) {
                _apiService.getMovie(movie, _apiKey)
            }
        } catch (e: Exception) {
            Log.e("MovieRepository", e.message ?: "No exception message available")
            return Resource.Error("An unknown error occurred while fetching data for the movie: $movie")
        }
        Log.d("Result", response.results.toString())
        return Resource.Success(response)
    }
}

当我 Log.d 我的 response.results 时,它会记录我从 api 调用的正确数据,但当我返回 Resource.Success(response) 时。我的 viewModel 中的 _movieResource 似乎没有更新为 Resource.Success(response)。此外,回到我的 MovieSearchResults 可组合项中,当调用 updateMovieResource 方法时,when 语句似乎没有注意到 _movieResource 在开始时更新为 Resource.Loading() 。我完全坚持这一点,感觉我在 MutableLiveData 上做错了什么,但我不完全确定。请帮助我!

当 updateMovieResource 完成运行并最终返回 Resource.Empty() 时,我已经记录了返回预期 api 响应的结果以及我的 movieResource。之后,我尝试将 MutableLiveData 更改为标准 mutableStateOf() 但这是不可能的,因为我有多个不同的资源响应。

kotlin resources state viewmodel
1个回答
0
投票

已修复我通过将 movieResource val 从 MovieSearchResults 方法移动到主 Create 方法并将其作为参数提供给 MovieSearchResults 方法解决了我的问题。

© www.soinside.com 2019 - 2024. All rights reserved.