While I updating some parts of my app, I think I doing some mistake or something is missing that causes this problem, the problem is happening when I tried to save any item to the favorites table, and after I saved it I open the same item (fragment details again) I should see the favorite icon (heart icon) filled with red color which means the item is already saved and If I click on it again it should be removed and so on...
now I see the item saved but when I click the back button and click on the item again the icon doesn't change and that's meaning the user can save it again (which causes duplicated items in recyclerView)
Problem in GIF
here's my code
FavoritesEntity class
@Parcelize
@Entity(tableName = "favorites")
data class FavoritesEntity(@PrimaryKey(autoGenerate = true) val id: Int, val item: Item) : Parcelable
Database class
@Database(
entities = [Item::class, FavoritesEntity::class],
version = 1,
exportSchema = false
) //@TypeConverters(Converters.class)
//@TypeConverters(Converters.class)
//@TypeConverters(Converters.class)
@TypeConverters(ItemTypeConverter::class)
abstract class ItemsDatabase : RoomDatabase() {
// private static ItemsDatabase INSTANCE;
abstract val itemDAO: ItemDAO
companion object {
@Volatile
private var INSTANCE: ItemsDatabase? = null
@Synchronized
fun getInstance(context: Context): ItemsDatabase {
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(
context.applicationContext,
ItemsDatabase::class.java,
"items_database"
).fallbackToDestructiveMigration()
.build()
return INSTANCE!!
}
return INSTANCE as ItemsDatabase
}
}
}
ItemDAO
@Dao
interface ItemDAO {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertItem(item: Item)
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertFavorites(favoritesEntity: FavoritesEntity)
@get:Query("SELECT * FROM FAVORITES")
val getAllFavorites: Flow<List<FavoritesEntity>>
@Delete
suspend fun deleteFavorite(favoritesEntity: FavoritesEntity)
@Query("DELETE FROM FAVORITES")
suspend fun deleteAllFavorites()
@Query("SELECT * FROM item_table order by datetime(published) DESC")
fun getAlItems(): Flow<List<Item>>
@Query("SELECT * FROM item_table WHERE title like '%' || :keyword || '%' ")
suspend fun getItemsBySearch(keyword: String?): List<Item>
}
DetailsViewModel
@HiltViewModel
class DetailsViewModel @Inject constructor(
private val mainRepository: MainRepository,
private val dataStoreRepository: DataStoreRepository
) : ViewModel() {
private val _favoritesPostList = MutableLiveData<List<FavoritesEntity>>()
val favoritesPostList: LiveData<List<FavoritesEntity>> get() = _favoritesPostList
fun getFavoritePosts() {
viewModelScope.launch {
mainRepository.localDataSource.getAllFavorites().collect {
_favoritesPostList.value = it
}
}
}
val readRecyclerViewPortraitLayout =
dataStoreRepository.readRecyclerViewPortraitLayout.asLiveData()
val readRecyclerViewLandscapeLayout =
dataStoreRepository.readRecyclerViewLandscpaeLayout.asLiveData()
fun saveRecyclerViewPortraitLayout(layout: String) {
viewModelScope.launch {
dataStoreRepository.saveRecyclerViewPortraitLayout(layout)
}
}
fun saveRecyclerViewLandscapeLayout(layout: String) {
viewModelScope.launch {
dataStoreRepository.saveRecyclerViewLandscapeLayout(layout)
}
}
fun insertFavorites(favoritesEntity: FavoritesEntity) {
viewModelScope.launch(Dispatchers.Default) {
mainRepository.localDataSource.insertFavorites(favoritesEntity)
}
}
fun deleteFavoritePost(favoritesEntity: FavoritesEntity) {
viewModelScope.launch(Dispatchers.IO) {
mainRepository.localDataSource.deleteFavorite(favoritesEntity)
}
}
fun deleteAllFavorites() {
viewModelScope.launch(Dispatchers.IO) {
mainRepository.localDataSource.deleteAllFavorites()
}
}
}
DetailsActivity
@AndroidEntryPoint
class DetailsActivity : AppCompatActivity() {
private var _binding: ActivityDetailsBinding? = null
private val binding get() = _binding!!
private var url: String? = null
private var title: String? = null
private var content: String? = null
private var youtubeThumbnailImageSrc: String? = null
private var youTubeLink: String? = null
private var youtubeThumbnailImageSetVisibility: Int? = null
private var html: Spannable? = null
private val detailsViewModel: DetailsViewModel by viewModels()
private var postItem: Item? = null
private var postFavoritesSaved = false
private var postFavoritesSavedId = 0
private var menuItem: MenuItem? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
_binding = ActivityDetailsBinding.inflate(layoutInflater)
setContentView(binding.root)
setSupportActionBar(binding.toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.setDisplayShowHomeEnabled(true)
binding.progressBar.visibility = View.VISIBLE
Log.d(
TAG,
"onCreate checkSavedFavoritesItems: $postFavoritesSavedId"
)
postItem = if (intent.extras!!.containsKey("postItem")) {
intent.getParcelableExtra("postItem")!!
} else {
val favoriteItem: FavoritesEntity = intent.getParcelableExtra("favoriteItem")!!
favoriteItem.item
}
}
override fun onDestroy() {
super.onDestroy()
changeMenuItemIcon(menuItem, R.drawable.ic_favorite_border)
binding.fab.setOnClickListener(null)
adRequest = null
_binding = null
}
private fun changeMenuItemIcon(menuItem: MenuItem?, icFavoriteBorder: Int) {
menuItem?.setIcon(icFavoriteBorder)
}
private fun checkSavedFavoritesItems(menuItem: MenuItem?) {
detailsViewModel.favoritesPostList.observe(this) { favoritesEntity ->
try {
favoritesEntity.forEach {
if (it.item.id == postItem?.id) {
changeMenuItemIcon(menuItem, R.drawable.ic_favorite)
postFavoritesSavedId = it.id
Log.d(TAG, "checkSavedFavoritesItems: $postFavoritesSavedId")
postFavoritesSaved = true
}
}
} catch (exception: Exception) {
Log.e(TAG, "checkSavedFavoritesItems: " exception.message)
}
}
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.details_menu, menu)
menuItem = menu.findItem(R.id.action_add_to_favorites)
checkSavedFavoritesItems(menuItem)
return true
}
override fun onOptionsItemSelected(menuItem: MenuItem): Boolean {
when {
menuItem.itemId == R.id.action_add_to_favorites && !postFavoritesSaved -> {
saveTogFavorites(menuItem)
}
menuItem.itemId == R.id.action_add_to_favorites && postFavoritesSaved -> {
removePostFromFavorites(menuItem)
}
menuItem.itemId == android.R.id.home -> this.finish()
}
return super.onOptionsItemSelected(menuItem)
}
private fun saveTogFavorites(menuItem: MenuItem) {
val favoritesEntity = postItem?.let {
FavoritesEntity(0, it)
}
if (favoritesEntity != null) {
detailsViewModel.insertFavorites(favoritesEntity)
}
menuItem.setIcon(R.drawable.ic_favorite)
Snackbar.make(binding.root, "Saved", Snackbar.LENGTH_LONG).show()
postFavoritesSaved = true
}
private fun removePostFromFavorites(menuItem: MenuItem) {
val favoritesEntity = postItem?.let { FavoritesEntity(postFavoritesSavedId, it) }
Log.d(
TAG, "checkSavedFavoritesItems: $postFavoritesSavedId"
)
if (favoritesEntity != null) {
detailsViewModel.deleteFavoritePost(favoritesEntity)
}
menuItem.setIcon(R.drawable.ic_favorite_border)
Snackbar.make(
binding.root,
"Post deleted from favorites", Snackbar.LENGTH_LONG
).show()
postFavoritesSaved = false
}
I tried to check for postFavoritesSavedId
in the log and I got 0 eachtime, so I tried to change it to get the item itself long ID instead favoritesEntity incremental id but doesn't work
CodePudding user response:
in this method checkSavedFavoritesItems
you observsed in favoritesEntity
but you forgot to call getFavoritePosts
method because of that this problem happend