Home > Software design >  Retrieve Firebase data using Coroutines
Retrieve Firebase data using Coroutines

Time:05-26

I'm trying to rewrite my program and start using Kotlin Coroutines. That is my function to retrieve a list of products for a given group. After debugging it looks like everything is correct.

class FirebaseRepository {

    private val db = FirebaseFirestore.getInstance()
    private val auth = FirebaseAuth.getInstance()

    fun getCurrentUserId(): String{
        return auth.currentUser!!.uid
    }

    suspend fun getLista(): MutableLiveData<List<Produkt>> {
        val result = MutableLiveData<List<Produkt>>()
        val lista = mutableListOf<Produkt>()
        db.collection(Constants.GROUP)
            .document("xGRWy21hwQ7yuBGIJtnA")
            .collection("Przedmioty")
            .orderBy("dataDodaniaProduktu", Query.Direction.DESCENDING)
            .get().await().forEach {

                val singleProdukt = it.toObject(Produkt::class.java)
                singleProdukt.produktId = it.id
                lista.add(singleProdukt)
                result.postValue(lista)
            }
        return result
    }

That is my ViewModel class:

    class ListaViewModel: ViewModel() {

    private val repository = FirebaseRepository()
    var _produkty =  MutableLiveData<List<Produkt>>()
    val produkty : LiveData<List<Produkt>> = _produkty


    init {
        viewModelScope.launch {
            _produkty = repository.getLista()
        }
    }

And finally in my fragment I'm trying to observe live data but looks like nothing is being passed to my adapter. What am I doing wrong?

class ListaFragment : Fragment(), ListaAdapter.OnItemClickListener {

    private var _binding: FragmentListaBinding? = null
    private val binding get() = _binding!!
    private lateinit var recyclerView : RecyclerView

    private lateinit var listAdapter : ListaAdapter
    private val listaViewModel by viewModels<ListaViewModel>()


    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
        _binding = FragmentListaBinding.inflate(inflater, container, false)
        recyclerView = binding.recyclerView

        listAdapter = ListaAdapter(emptyList(), this)
        recyclerView.adapter = listAdapter // Zapobiega "No adapter attached; skipping layout"
        recyclerView.layoutManager = LinearLayoutManager(requireActivity())
        recyclerView.setHasFixedSize(true)
    
     listaViewModel.produkty.observe(viewLifecycleOwner, Observer {
            listAdapter = ListaAdapter(it, this)
    }
    return binding.root
    }

CodePudding user response:

Try replacing this:

val produkty : LiveData<List<Produkt>> = _produkty

with this

val produkty : LiveData<List<Produkt>> get() = _produkty

This way you'll have "getter" rather than "initializer". Initializer will compute its value once (to the empty live data) and after you reassign that var it won't change the value of your val.

CodePudding user response:

The problem in your code lies in the fact that you're creating a new instance of your ListaAdapter class inside the observe() method, without notifying the adapter about the changes. That's the reason why you're getting no results in the adapter. To solve this, simply create a method inside your adapter class:

fun setProduktList(produktList: List<Produkt>) {
    this.produktList = produktList
    notifyDataSetChanged()
}

Then inside your observe() method, use the following line of code:

listaViewModel.produkty.observe(viewLifecycleOwner, Observer {
    //listAdapter = ListaAdapter(it, this) //Removed
    listAdapter.setProduktList(it)            
  • Related