Home > Software engineering >  How to display items loading while data is being fetched from Firebase android kotlin
How to display items loading while data is being fetched from Firebase android kotlin

Time:12-02

I have a RecyclerView and my Fragment. I am getting data from Firebase Realtime Database into a RecyclerView.

I need to make it so that while the data is loading, I see some kind of loading effect. How can i do this?

Code from my Fragment:

private var _binding: FragmentDayDetailBinding? = null
private val binding get() = _binding!!

private var ref: DatabaseReference? = null
private lateinit var adapter: DayDetailAdapter

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

    setupRecyclerView()
    initDatabase()

    return binding.root
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    readFromDatabase()
}

private fun setupRecyclerView() {
    adapter = DayDetailAdapter()
    binding.recyclerView.layoutManager = LinearLayoutManager(requireContext())
    binding.recyclerView.adapter = adapter
}

private fun initDatabase() {
    FirebaseApp.initializeApp(requireContext())

    ref = FirebaseDatabase.getInstance()
        .getReference("IMIT")
        .child("groups")
}

private fun readFromDatabase() {
    ref?.addValueEventListener(object: ValueEventListener {
        override fun onDataChange(snapshot: DataSnapshot) {
            if (snapshot.exists()) {

                val list = ArrayList<Day>()

                for (daySnapshot in snapshot.children) {
                    val day = daySnapshot.getValue(Day::class.java)

                    list.add(day!!)
                }

                adapter.submitList(list)

            } else {
                binding.apply {
                    lrDbEmpty.visibility = View.VISIBLE
                    recyclerView.visibility = View.INVISIBLE
                }
            }
        }

        override fun onCancelled(error: DatabaseError) {

        }
    })
}

override fun onDestroyView() {
    super.onDestroyView()
    _binding = null
}

Code from RecyclerView Adapter:

class ViewHolder(private val binding: ItemSubjectDetailBinding): RecyclerView.ViewHolder(binding.root) {

    fun bind(day: Day) = with(binding) {
        tvSubject.text = day.subject
        tvInfo.text = "${day.teacher}, ${day.type}"
        tvTime.text = day.time
        tvAud.text = day.classroom
    }

    companion object {
        fun from(parent: ViewGroup): ViewHolder {
            val layoutInflater = LayoutInflater.from(parent.context)
            val binding = ItemSubjectDetailBinding.inflate(layoutInflater, parent, false)
            return ViewHolder(binding)
        }
    }
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
    return ViewHolder.from(parent)
}

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
    with(holder) {
        bind(getItem(position))
    }
}

class ItemComparator: DiffUtil.ItemCallback<Day>() {
    override fun areItemsTheSame(oldItem: Day, newItem: Day): Boolean {
        return oldItem == newItem
    }

    override fun areContentsTheSame(oldItem: Day, newItem: Day): Boolean {
        return oldItem == newItem
    }
}

CodePudding user response:

You already in half the way

Create a progressBar in the center of the fragment

<ProgressBar
      android:id="@ id/progress_bar"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      />

Keep it visible until the data fetched (onDataChange Called) then hide the progressBar

override fun onDataChange(snapshot: DataSnapshot) {

    binding.progressBar.visibility = View.GONE

    if (snapshot.exists()) {
        // rest of your code
    }
}
  • Related