android - 使用 MVVM + Coroutines 将实时数据库值获取到 ArrayList
问题描述
我想使用协程和 MVVM 从实时数据库中获取数据列表,并将它们放入 recyclerview。它运行,但来自实时数据库的数据是在 recyclerview.adapter 初始化之后添加的,因此将 list.size 返回为 0
视图模型.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"
))
}
}
片段.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()首先返回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()
}
}
}
推荐阅读
- python-3.x - 从 Python 3 中的文本中一起删除两个单词(短语)
- node.js - 使用接口映射来自 http 请求的嵌套数组响应
- javascript - 将身份发送到控制器发布操作
- elasticsearch - 仅当数组中存在所有值时,弹性搜索才选择文档
- c# - 我在 Windows 10 上用 VS2017 编译了一个安装项目。它可以在 XP 上运行吗?
- ionic-framework - 离子梯度路径问题
- javascript - RegularExpressionValidator:不允许使用 EnableClientScript 破折号或破折号
- c# - C# WPF NotifyIcon BalloonTip 和 TrayBalloonTipClicked 事件
- haskell - How exactly does `IO`'s >>= work under the hood?
- latex - 使用彩色行时,如何消除表格行和列之间的间距?