androidkotlinandroid-recyclerviewsharedpreferencesandroid-adapter

The data from SharedPreferences doesn't update unless I scroll down the RecyclerView Android Kotlin


The problem is that when I click the "Add to Favorites" button for the first time, the image changes and the data is saved to SharedPreferences. However, when I click the same button again, nothing changes. It's only when I scroll a little bit down (until the item disappears from the screen) and then scroll back up that the button I clicked before scrolling down finally shows the change.

I'm trying to keeping add favorite data in sharedPreferences





import android.content.Context
import android.content.SharedPreferences
import com.example.myapplication.data.model.CocktailModel
import com.google.gson.Gson

class SharedPrefs(context: Context) {
    private val preferences: SharedPreferences? =
        context.getSharedPreferences("FavoriteStatus", Context.MODE_PRIVATE)
    fun addFavorite(cocktail: CocktailModel) {
        val favorites = getFavorites()
        favorites.add(cocktail)
        saveFavorites(favorites)
    }

    fun removeFavorite(cocktail: CocktailModel) {
        val favorites = getFavorites()
        favorites.remove(cocktail)
        saveFavorites(favorites)
    }

    fun getFavorites(): MutableList<CocktailModel> {
        
        val json = preferences?.getString("favorites", "[]")
        val favorites = Gson().fromJson(json, Array<CocktailModel>::class.java)
        return favorites?.toMutableList() ?: mutableListOf()
    }

   
    private fun saveFavorites(favorites: List<CocktailModel>) {
        val json = Gson().toJson(favorites)
        preferences?.edit()?.putString("favorites", json)?.apply()
    }
}

And my recycler view adapter is =




package com.example.myapplication.ui.adapter




import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.example.myapplication.R
import com.example.myapplication.SharedPrefs
import com.example.myapplication.data.model.CocktailModel
import com.example.myapplication.databinding.FeedRowBinding


class FeedAdapter(private val cocktailList : ArrayList<CocktailModel>) :
    RecyclerView.Adapter<FeedAdapter.FeedViewHolder>() {


    class FeedViewHolder(private val binding: FeedRowBinding, private val preferenceManager: SharedPrefs) :
        RecyclerView.ViewHolder(binding.root) {
        fun bind(cocktailModel: CocktailModel) {
            binding.CocktailTitle.text = cocktailModel.strDrink
            Glide.with(binding.imageView.context)
                .load(cocktailModel.strDrinkThumb)
                .into(binding.imageView)

            val isFavorite = preferenceManager.getFavorites().contains(cocktailModel)

            updateHeartButton(isFavorite)

            // favori butonuna tiklandiginda favoriye ekliyse kaldiriyor, degilse ekliyor
            binding.heartButton.setOnClickListener {
                if (isFavorite) {
                    preferenceManager.removeFavorite(cocktailModel)
                } else {
                    preferenceManager.addFavorite(cocktailModel)
                }
                updateHeartButton(!isFavorite)
            }

        }

        // favori butonunun durumunu guncelleyen fonksiyon buna gore image degistiriyoruz
        private fun updateHeartButton(isFavorite: Boolean) {
            if (isFavorite) {
                binding.heartButton.setImageResource(R.drawable.heart)
            } else {
                binding.heartButton.setImageResource(R.drawable.heart2)
            }
        }
    }


    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FeedViewHolder {
        val binding = FeedRowBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return FeedViewHolder(binding, SharedPrefs(parent.context))

    }

    override fun getItemCount(): Int {
        return cocktailList.size
    }

    override fun onBindViewHolder(holder: FeedViewHolder, position: Int) {
        holder.bind(cocktailList[position])
    }
    fun updateData(cocktails: List<CocktailModel>) {
        cocktailList.clear()
        cocktailList.addAll(cocktails)
       
    }

}





Solution

  • So the root cause of your issue is this line :

    val isFavorite = preferenceManager.getFavorites().contains(cocktailModel)
    

    isFavorite value gets loaded only once when that item's viewholder is loaded by the recyclerview and its a val. So, even after you tap the button, it only works once. To solve this issue, you need to first convert this to a var and then change the onClick code to the following :

    var isFavorite = preferenceManager.getFavorites().contains(cocktailModel)
    updateHeartButton(isFavorite)
    binding.heartButton.setOnClickListener {
                    if (isFavorite) {
                        preferenceManager.removeFavorite(cocktailModel)
                    } else {
                        preferenceManager.addFavorite(cocktailModel)
                    }
                    isFavorite = !isFavorite 
                    // -> updateHeartButton(!isFavorite)
                    updateHeartButton(isFavorite)
                }