Search code examples
androidkotlinandroid-recyclerviewandroid-livedata

MutableLiveData, RecyclerView refresh on delete


I'm a totally newby using Kotlin and I'm trying to create my first app with a lot of test and error (and have worked till now).

My problem is that I have created a recyclerview that have rows from files in firestore (everything correct), in each row a put a button to delete that file from firestore (works smoothly), but after clicking the button the list is not updated so I still see the file that I just removed...

Let me share with you and please help me identify the error cos I did this with room and the list was refreshing acordingly.

My Fragment:

class SharingFragment : Fragment() {
    override fun onViewStateRestored(savedInstanceState: Bundle?) {
        super.onViewStateRestored(savedInstanceState)
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        val binding: FragmentSharesBinding = DataBindingUtil.inflate(
            inflater, R.layout.fragment_shares, container, false)
        val application = requireNotNull(this.activity).application
        val viewModelFactory = SharingViewModelFactory(application)
        val sharingViewModel = ViewModelProvider(this,viewModelFactory).get(
            SharingViewModel::class.java)

        sharingViewModel.getSharedWithMe().observe(this , Observer { list->
            // set the layout manager and the adapter for the recycler view
            binding.listaRecyclerView.layoutManager = LinearLayoutManager(application)
            binding.listaRecyclerView.adapter = InsuranceAdapter(context!!,list)
        })
        binding.sharingViewModel = sharingViewModel
        val root: View = binding.root
        return root
    }
}

My ViewModel (SharingViewModel):

class SharingViewModel(
    application: Application
) : AndroidViewModel(application)
{
    var listReturn: MutableLiveData<List<String>>

    init {
        listReturn = MutableLiveData(listOf())
    }

    fun getSharedWithMe() : MutableLiveData<List<String>> {

        var auth = Firebase.auth
        val storage = Firebase.storage
        var storageRef = storage.reference
        val databaseRef = storageRef.child("shared/${auth!!.currentUser!!.email}")

        var listFile = databaseRef.listAll()

        listFile.addOnSuccessListener { (items, prefixes) ->
                var list: MutableList<String> = mutableListOf()
                items.forEach { item ->
                    list.add(item.name)
                }
                listReturn.value = listReturn.value?.plus(list)
            }
            .addOnFailureListener {
                // Uh-oh, an error occurred!
            }
        //Wait to receive the listall
        while(listFile.isComplete==false) {Thread.sleep(1000)}
        return listReturn
    }

    fun deleteSharedWithMe(file: String) {

        var auth = Firebase.auth
        val storage = Firebase.storage
        var storageRef = storage.reference
        val fileRef =
            storageRef.child("shared/${auth!!.currentUser!!.email}/${file}")
        fileRef.delete()
        listReturn.value = listReturn.value!!.toMutableList().apply {
            remove(file)
        }.toList()
    }
}

and my adapter:

class InsuranceAdapter(val context : Context,val list : List<String>) : RecyclerView.Adapter<InsuranceAdapter.ViewHolder>() {
    // Inner ViewHolder class
    class ViewHolder(val binding : SharingListBinding) : RecyclerView.ViewHolder(binding.root){}

        // function to inflate the layout for each contact and create a new ViewHolder instance
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        return ViewHolder(
            SharingListBinding.inflate(LayoutInflater.from(parent.context),parent,false)
        )
    }

    // function to bind the data to the view elements of the ViewHolder
    @RequiresApi(Build.VERSION_CODES.O)
    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.binding.fileTextview.text = list[position]

        // delete button onClickListener to delete the
        // file from firestore and notify the
        // adapter of the change
        holder.binding.deleteButton.setOnClickListener{
            val application = requireNotNull(Application())
            val sharingViewModel = SharingViewModel(Application())

            //TODO borrar de Firebase
            sharingViewModel.deleteSharedWithMe(list[position])

           // dao.delete(list[position]) //this was working when I was using Room and deleting from the DB was refreshing the list
            notifyItemChanged(position)
            notifyDataSetChanged()
        }
    }


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

}

So, what I have followed is to use the function inside the viewmodel to delete the file, but I have no idea why the list is not refreshing, any ideas?


Solution

  • The reason why the list is not refreshing is that you are creating a new instance of the SharingViewModel in your InsuranceAdapter class, which is not the same instance that is observed by the SharingFragment

    In your fragment:

    binding.listaRecyclerView.adapter = InsuranceAdapter(context!!, list, sharingViewModel) // pass the ViewModel instance to the adapter
    

    In your adapter

    class InsuranceAdapter(
        val context: Context,
        val list: List<String>,
        val viewModel: SharingViewModel // pass the ViewModel instance from the Fragment
    )
    
     viewModel.deleteSharedWithMe(list[position]) // use the existing ViewModel instance