我很难解决一个问题。所以基本上我正在尝试将我的数据库从Android中的Room迁移到Firebase。我已经能够按照我试图保存在Room Database中的类似结构在Firebase中存储我的值。
现在我面临的主要问题是从Firebase中检索值。更具体地说,我正在使用嵌套的回收器视图,所以我有一个有点复杂的结构。我将在下面解释它。
因此,数据的工作原理是,有楼层,每层楼有房间,每个房间有机器。所以它在层次结构中。当我使用本地数据库时,我创建了一个函数,在我的ViewModel中处理此功能:
它看起来是这样的:
fun load() {
//Observing all floors
getAllFloors.observeForever(Observer {
viewModelScope.launch(Dispatchers.Main) {
/** Converting list of floors to a distinct and sorted floor list
* Input -> [0,0,1,2,3,4,2,4,1,3], Output -> [0,1,2,3,4]
*/
val distinctFloorNames = it.distinct().sorted()
val floorsList = mutableListOf<FloorsDataClass>()
val devicesList = mutableListOf<String>()
//Loop over distinct floors for getting each floor
for (floorName in distinctFloorNames) {
//At each floor prepare a list of rooms
val rooms = repository.getAllRooms(floorName)
//Getting distinct (in case rooms gets repeated -> only during testing) and sorted rooms
val distinctRoomNames = rooms.distinct().sorted()
Timber.d("Floor: $floorName, Rooms: $distinctFloorNames")
val roomsList = mutableListOf<RoomsDataClass>()
//Loop over rooms in the floor
for (roomName in distinctRoomNames) {
//In each room prepare a list of devices
val devicesName = repository.getAllDevices(roomName)
val distinctDeviceName = devicesName.distinct().sorted()
//Transform the list of string to list of DeviceClassObject
val deviceData = mutableListOf<DevicesDataClass>()
//For each device get the attached machine
for (device in distinctDeviceName) {
//Get the machine associated with the device
val machine = repository.getMachine(device)
Timber.d("Machine: $machine")
//Attach the device and machine to the [DevicesDataClass Object]
deviceData.add(DevicesDataClass(device, machine))
/**Attach the room name and the devices list to the
*[RoomDataClass Object]
**/
roomsList.add(RoomsDataClass(roomName, deviceData))
//Saving devices in a list for managing
devicesList.add(device)
}
}
/**Add the room list to the floor object and
add the floor to the floor list **/
floorsList.add(FloorsDataClass(floorName, roomsList))
}
//Sending the list as livedata to be further observed - from add details for device - manage devices fragment
devicesLiveData.postValue(devicesList)
/** Post the complete value of floorList in the floorListLiveData which will be
* observed from the [ControlPanelFragment]
*/
floorListLiveData.postValue(floorsList)
Timber.d("$floorsList")
}
})
}
现在,为了显示我刚刚观察到的这个floorsList
的数据,然后将它传递给我的嵌套适配器,它会相应地显示数据。
我正试图以类似的方式从Firebase获取数据。我已经达到了一个地步,我甚至可以获取我的楼层和每个楼层的房间,但问题是在获取机器时出现的。
基本上我在我的项目中使用了两个ValueEventListener
。我使用来自其中一个侦听器的值来填充我的数据。但是由于从Firebase阅读数据是异步的,我的数据字段显示为空,因为我试图在数据来自数据库之前使用该数据。这是主要问题。
火座结构
从Firebase阅读值的代码
private fun readRoomsAndFloorFromFirebase(): List<FloorsDataClass> {
val roomsDataClass: MutableList<RoomsDataClass> = mutableListOf()
val devicesDataClass: MutableList<DevicesDataClass> = mutableListOf()
val floorsDataClass: MutableList<FloorsDataClass> = mutableListOf()
val listener = object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
var floors: FloorsDataClass
// Log.d(TAG, "Data: ${snapshot}")
for (i in snapshot.children) {
Log.i(TAG, "Data: $i")
// floor = "${i.key}"
for (j in i.children) {
Log.i(TAG, "Value: ${j.key}")
// roomsList.add("${j.key}")
val listener = object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
// Log.w(TAG, "Listener: ${snapshot.child("Device ID").value}")
val device = snapshot.child("Device ID").value.toString()
val machine = snapshot.child("Machine").value.toString()
devicesDataClass.add(DevicesDataClass(device, machine))
}
override fun onCancelled(error: DatabaseError) {}
}
//Getting the list of devices and saving it with particular room
roomsDataClass.add(RoomsDataClass("${j.key}", devicesDataClass))
realtime.child("USERS").child(auth.uid!!).child(
"ADDED DEVICES"
).child("${i.key}").child("${j.key}")
.addValueEventListener(listener)
}
//Storing the particular floor with room data class values
floors = FloorsDataClass("${i.key}", roomsDataClass)
floorsDataClass.add(floors)
}
Log.e(TAG, "List 1: $floorsDataClass")
}
override fun onCancelled(error: DatabaseError) {}
}
realtime.child("USERS").child(auth.uid!!).child("ADDED DEVICES")
.addValueEventListener(listener)
Log.e(TAG, "List: $floorsDataClass")
return floorsDataClass
}
数据类别:
第一个
另外,我想从firebase结构中读取数据,这样我就有了一个包含第一个元素(即第一层)的对象,在该对象中,它可以存储房间,然后进一步存储该房间的设备。一旦房间循环完成,我想继续并将其与楼层一起保存。
如果需要更多的代码或ss来理解问题,请评论。
1条答案
按热度按时间xzlaal3s1#
我建议您使用KotlinFlow或Android LiveData来设置观察器,以便在数据准备就绪时执行一些工作。
然后在Activity/Fragment中观察LiveData并在回调中设置RecyclerView。我鼓励您回顾this tutorial on LiveData!