使用 MVVM + Coroutines 获取实时数据库值到 ArrayList

Get Realtime Database value to ArrayList using MVVM + Coroutines

我想使用协程和 MVVM 从实时数据库中获取数据列表,并将它们放入 recyclerview。它运行但是实时数据库中的数据是在 recyclerview.adapter 初始化后添加的,thus returning list.size to 0

ViewModel.kt

class DasarhukumdetailsViewModel : ViewModel() {
val database = FirebaseDatabase.getInstance().reference
var dasarHukumList = ArrayList<DasarHukum>()

fun getDHData(KEYVALUE: String?) = liveData(Dispatchers.Main.immediate) {
    val postListener = object : ValueEventListener {
        override fun onDataChange(snapshot: DataSnapshot) {
            for (snapshot in snapshot.children) {
                val res = snapshot.getValue(DasarHukum::class.java)
                Log.d("dataAdd", "Adding: ${res?.filename}")
                dasarHukumList.add(res!!)
            }
        }

        override fun onCancelled(databaseError: DatabaseError) {
            // Getting Post failed, log a message
            Log.w("readDHList", "loadPost:onCancelled", databaseError.toException())
            throw databaseError.toException()
        }
    }
    try {
        if (KEYVALUE != null) {
            database.child("dasarhukum").child(KEYVALUE).addValueEventListener(postListener)
        }
        emit(Resource.success(dasarHukumList))
    } catch (e: Exception) {
        emit(Resource.error(
            null,
            e.message ?: "Unknown Error"
        ))
    }
}

Fragment.kt

override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
   [...]
    observerSetup(KEYVALUE)
    rvSetup()
    return binding.root
}
fun observerSetup(keyvalue: String?) {
    viewModel.getDHData(keyvalue).observe(viewLifecycleOwner, {
        when (it.status) {
            Status.SUCCESS -> {
                it?.data.let { dhList ->
                    dasarHukumAdapter.dasarhukumList = dhList
                    dasarHukumAdapter.notifyDataSetChanged()
                }
            }
            Status.ERROR -> {
                Toast.makeText(context, "Error getting documents: ${it.message}", Toast.LENGTH_LONG)
                Log.e("realDB", it.message!!)
            }
        }
    })
}
fun rvSetup() {
    with(binding.rvDasarHukum) {
        layoutManager = LinearLayoutManager(context)
        setHasFixedSize(true)
        adapter = dasarHukumAdapter
    }
}

RVAdapter.kt

class DasarHukumAdapter : RecyclerView.Adapter<DasarHukumAdapter.DasarHukumViewHolder>() {
var dasarhukumList: List<DasarHukum>? = null
    set(value) {
        notifyDataSetChanged()
        field = value
    }

class DasarHukumViewHolder(private val binding: ItemDasarhukumBinding) :
    RecyclerView.ViewHolder(binding.root) {
    fun bind(dasarHukum: DasarHukum?) {
        binding.dasarhukum = dasarHukum
        binding.executePendingBindings()
    }
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DasarHukumViewHolder {
    val layoutInflater = LayoutInflater.from(parent.context)
    val binding = ItemDasarhukumBinding.inflate(layoutInflater, parent, false)
    return DasarHukumViewHolder(binding)
}

override fun onBindViewHolder(holder: DasarHukumViewHolder, position: Int) {
    val dasarHukum = dasarhukumList?.get(position)
    Log.d("dhVH", "Adding: ${dasarHukum?.name}")
    holder.bind(dasarHukum)
}

override fun getItemCount(): Int {
    Log.d("dhCount", "List size: ${dasarhukumList?.size}")
    return dasarhukumList?.size ?: 0
}

recyclerview 如何等待 viewmodel.getDHData() 到 returns arraylist 然后初始化以便它可以显示给 recyclerview?

当您尝试使用以下代码行发出结果时:

emit(Resource.success(dasarHukumList))

数据尚未完成加载,因此列表大小为零。 Firebase API 是异步的,因此您需要等待数据才能在另一个操作中使用它。因此,任何需要来自实时数据库的数据的代码都需要位于“onDataChange()”方法内,或者从那里调用。因此,在这种情况下,最简单的解决方案是在回调中移动有关发出结果的逻辑:

fun getDHData(KEYVALUE: String?) = liveData(Dispatchers.Main.immediate) {
    val postListener = object : ValueEventListener {
        override fun onDataChange(snapshot: DataSnapshot) {
            for (snapshot in snapshot.children) {
                val res = snapshot.getValue(DasarHukum::class.java)
                Log.d("dataAdd", "Adding: ${res?.filename}")
                dasarHukumList.add(res!!)
            }
            try {
                if (KEYVALUE != null) {
                    database.child("dasarhukum").child(KEYVALUE).addValueEventListener(postListener)
                }
                emit(Resource.success(dasarHukumList))
            } catch (e: Exception) {
            emit(Resource.error(
                null,
                e.message ?: "Unknown Error"))
            }
        }

        override fun onCancelled(databaseError: DatabaseError) {
            // Getting Post failed, log a message
            Log.w("readDHList", "loadPost:onCancelled", databaseError.toException())
            throw databaseError.toException()
        }
    }
}