我目前正在编写一个显示电影列表的应用程序。
我正在使用带有 3 个选项卡的底部导航栏:趋势、发现和收藏夹。每个都显示电影列表,用户可以按下电影并转到详细信息片段。详细信息片段有一个复选框,可以将电影添加到收藏夹选项卡。
复选框有效,电影已添加到收藏夹,但复选框状态有问题。例如,如果我从详细信息片段(例如从趋势选项卡)添加电影,然后转到收藏夹选项卡并按电影以转到详细信息片段,则不会选中。
此外,如果我回到趋势并按下电影,它也不会被检查。
任何帮助是极大的赞赏。
MoviesDetailsFragment.kt
package com.example.moviesapp.ui.Fragments
import android.os.Bundle
import android.view.View
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.navArgs
import com.bumptech.glide.Glide
import com.example.moviesapp.R
import com.example.moviesapp.databinding.FragmentMoviesDetailsBinding
import com.example.moviesapp.network.MoviesFavorites
import com.example.moviesapp.network.MoviesResults
import com.example.moviesapp.ui.DaoViewModel
import com.example.moviesapp.ui.IMAGE_BASE_URL
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
@AndroidEntryPoint
class MoviesDetailsFragment() : Fragment(R.layout.fragment_movies_details) {
//We can get the movies from the args property
private val args by navArgs<MoviesDetailsFragmentArgs>()
private val daoViewModel by viewModels<DaoViewModel>()
private fun showToast(string: String) {
Toast.makeText(view?.context, string, Toast.LENGTH_SHORT).show()
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val binding = FragmentMoviesDetailsBinding.bind(view)
binding.apply {
val movie: MoviesResults.Movies = args.movie
val fav = MoviesFavorites(
movie.title,
movie.id,
movie.release_date,
movie.overview,
movie.vote_average,
movie.poster_path,
movie.original_language,
movie.isFavorite,
)
//When you are in fragment/activity, pass it to a glide.with because view is less efficient
Glide.with(this@MoviesDetailsFragment)
.load(IMAGE_BASE_URL + movie.poster_path)
//Have the textview visible only when image is visible
.error(R.drawable.ic_baseline_error_outline_24)
.fitCenter()
.into(coverPhoto)
title.text = movie.title
releaseDate.text = movie.release_date
language.text = movie.original_language
rating.text = movie.vote_average
plot.text = movie.overview
viewLifecycleOwner.lifecycleScope.launch {
fav.isFavorite = daoViewModel.preferencesFlow.first().favorite
}
favCheckbox.setOnClickListener {
if (favCheckbox.isChecked) {
fav.isFavorite = true
daoViewModel.addMovieToFavs(fav)
showToast("${fav.title} is added to your favorites")
} else {
fav.isFavorite = false
daoViewModel.deleteMovieFromFavs(fav)
showToast("${fav.title} is removed from your favorites")
}
}
}
}
}
DaoViewModel.kt
package com.example.moviesapp.ui
import androidx.lifecycle.*
import com.example.moviesapp.network.MoviesFavorites
import com.example.moviesapp.network.MoviesFavoritesRepository
import com.example.moviesapp.network.PreferencesManager
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
class DaoViewModel @Inject constructor(
private val repository: MoviesFavoritesRepository,
private val preferencesManager: PreferencesManager
) :
ViewModel() {
val favMovies: LiveData<List<MoviesFavorites>> = repository.favoriteMovies.asLiveData()
val preferencesFlow = preferencesManager.preferencesFlow
fun onFavorite(favorite: Boolean) {
viewModelScope.launch {
preferencesManager.updateFavorite(favorite)
}
}
fun addMovieToFavs(favorite: MoviesFavorites) {
viewModelScope.launch {
repository.insertFavorite(favorite)
}
}
fun deleteMovieFromFavs(favorite: MoviesFavorites) {
viewModelScope.launch {
repository.deleteFavorite(favorite)
}
}
class DaoViewModelFactory @Inject constructor(
private val repository: MoviesFavoritesRepository,
private val preferencesManager: PreferencesManager
) : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(DaoViewModel::class.java)) {
@Suppress("UNCHECKED_CAST")
return DaoViewModel(repository, preferencesManager) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
}
}
首选项管理器.kt
package com.example.moviesapp.network
import android.content.Context
import android.util.Log
import androidx.datastore.preferences.createDataStore
import androidx.datastore.preferences.edit
import androidx.datastore.preferences.emptyPreferences
import androidx.datastore.preferences.preferencesKey
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.map
import java.io.IOException
import javax.inject.Inject
import javax.inject.Singleton
private const val TAG = "PreferencesManager"
data class FilterPreferences(val favorite: Boolean)
@Singleton
class PreferencesManager @Inject constructor(@ApplicationContext context: Context) {
private val dataStore = context.createDataStore("user_preferences")
val preferencesFlow = dataStore.data
.catch { exception ->
if (exception is IOException) {
Log.e(TAG, "Error reading preferences", exception)
emit(emptyPreferences())
} else {
throw exception
}
}
.map { preferences ->
val favorites = preferences[PreferencesKeys.FAVORITES] ?: false
FilterPreferences(favorites)
}
suspend fun updateFavorite(favorites: Boolean) {
dataStore.edit { preferences ->
preferences[PreferencesKeys.FAVORITES] = favorites
}
}
private object PreferencesKeys {
val FAVORITES = preferencesKey<Boolean>("favorites")
}
}