我在构建小型电影库应用程序时遇到了问题。我的结构如下:我有一个 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() 但这是不可能的,因为我有多个不同的资源响应。
已修复我通过将 movieResource val 从 MovieSearchResults 方法移动到主 Create 方法并将其作为参数提供给 MovieSearchResults 方法解决了我的问题。