我有一个由三个回收者视图组成的结构。因此,有一个父回收器视图包含一个子回收器视图,而该子回收器视图又包含一个子回收器视图。
为了理解,就像第一个回收者视图是楼层总数。第二个回收者视图是房间总数,第三个回收者视图是设备总数。
我有一个房间数据库,我可以在其中编写查询以接收总楼层、房间、设备作为字符串列表。因为它们作为字符串值存储在数据库中。
对于查询楼层来说,这是一个简单的查询。为了查询房间,我传递楼层位置,为了查询连接的设备,我传递房间值。
该项目遵循 MVVM 架构,因此存在 DAO,数据从 DAO 传送到存储库,存储库进一步传送到 Viewmodel,然后使用 LiveData 从 Fragment 进行观察。
主要问题:所以大部分获取楼层、房间和设备的逻辑都发生在 ViewModel 内部。我尝试了多种方法通过使用 livedata 或挂起函数从房间数据库中获取数据。但在这些循环中插入数据类中的值时会出现问题。我显然做错了什么(下面给出的代码),因为显示的数据格式不正确。我得到了楼层和房间的列表,但这就像所有房间都添加到每个楼层,而不是每个楼层的单独值。类似地,应连接到各个房间的所有设备都连接到所有房间。
如果有人能帮我解决这个问题,那将会非常有帮助,因为我在过去的两天里陷入了困境。谢谢!下面给出了所有代码,如果您需要更多理解,请在评论中告诉我。
实体文件
@Entity(tableName = "added_device_information")
data class AddedDevicesInformation(
@ColumnInfo(name = "floor_name")
var floorName: String? = "",
@ColumnInfo(name = "room_name")
var roomName: String? = "",
@ColumnInfo(name = "machine_name")
var machineName: String? = "",
@ColumnInfo(name = "device_name")
var deviceName: String? = "",
@ColumnInfo(name = "factory_status")
var factoryStatus: Boolean? = false,
@PrimaryKey(autoGenerate = true)
var id: Int? = null,
) {
}
DAO file
@Dao
interface DevicesInformationDao {
@Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insertAddedDevicesToDatabase(addedDevicesInformation: AddedDevicesInformation)
//returns all floors in the database
@Query("SELECT floor_name from added_device_information")
fun readAllFloorsFromDatabase(): LiveData<List<String>>
//returns all rooms associated with a floor
@Query("SELECT room_name from added_device_information where floor_name =:floor")
suspend fun readAllRoomsOnAFloor(floor: String): List<String>
//Get all devices in a room
@Query("SELECT device_name from added_device_information where room_name =:room")
suspend fun readAllDevicesInRoom(room:String): List<String>
}
存储库文件
//This repository is for reading values from the database using [DevicesInformationDao]
class ControlPanelRepository(private val devicesInformationDao: DevicesInformationDao) {
val getAllFloors: LiveData<List<String>> = devicesInformationDao.readAllFloorsFromDatabase()
//for rooms associated with floors
suspend fun getAllRooms(floor: String): List<String> = devicesInformationDao.readAllRoomsOnAFloor(floor)
suspend fun getAllDevices(room: String): List<String> = devicesInformationDao.readAllDevicesInRoom(room)
}
ViewModel 文件(主要问题在这个文件中)
class ControlPanelViewModel(private val repository: ControlPanelRepository) : ViewModel() {
//Variable for getting all floors
private val _getAllFloors: LiveData<List<String>> = repository.getAllFloors
private val getAllFloors: LiveData<List<String>> = _getAllFloors
//setting FloorDataClass objects
private val floorListLiveData = MutableLiveData<List<FloorsDataClass>>()
val floorList: LiveData<List<FloorsDataClass>> get() = floorListLiveData
fun loadRooms() {
val floorsList = mutableListOf<FloorsDataClass>()
val roomsList = mutableListOf<RoomsDataClass>()
val devicesList = mutableListOf<DevicesDataClass>()
var distinctFloors: List<String>
var distinctRooms: List<String>
var distinctDevices: List<String>
getAllFloors.observeForever(Observer {
viewModelScope.launch(Dispatchers.Main) {
distinctFloors = it.distinct().sorted()
for (floorName in distinctFloors) {
val rooms = repository.getAllRooms(floorName)
distinctRooms = rooms.distinct()
for (roomName in distinctRooms) {
distinctDevices = repository.getAllDevices(roomName)
devicesList.add(DevicesDataClass(distinctDevices))
roomsList.add(RoomsDataClass(roomName, devicesList))
floorsList.add(FloorsDataClass(floorName, roomsList))
floorListLiveData.postValue(floorsList)
Timber.d("$floorsList")
}
}
}
})
}
}
片段文件:
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentControlPanelBinding.inflate(layoutInflater)
adapter = FloorsAdapter(activity)
controlPanelViewModel = ViewModelProvider(this, factory)[ControlPanelViewModel::class.java]
controlPanelViewModel.loadRooms()
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.rvFloors.adapter = adapter
binding.rvFloors.layoutManager = LinearLayoutManager(requireContext())
binding.rvFloors.setHasFixedSize(true)
controlPanelViewModel.floorList.observe(viewLifecycleOwner, Observer {
adapter.floorList(floors = it)
Timber.d("List is $it")
})
}
数据类别 -
楼层数据类
data class FloorsDataClass(val floor: String, val rooms: List<RoomsDataClass>) {
}
房间数据类
data class RoomsDataClass(val room:String, val devices: List<DevicesDataClass>) {
}
设备数据类
data class DevicesDataClass(val machine: List<String>) {
}
回收站视图适配器
open class FloorsAdapter(
private val activity: FragmentActivity?
) : RecyclerView.Adapter<FloorsAdapter.FloorViewHolder>() {
private var floorList = emptyList<FloorsDataClass>()
inner class FloorViewHolder(
val binding: ListItemControlPanelFloorsBinding,
val roomsAdapter: RoomsAdapter
) : RecyclerView.ViewHolder(binding.root) {}
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): FloorViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val binding = ListItemControlPanelFloorsBinding.inflate(layoutInflater, parent, false)
//Create adapter per floor
val adapter = RoomsAdapter(activity)
binding.rvRoomControlPanel.adapter = adapter
binding.rvRoomControlPanel.layoutManager = LinearLayoutManager(activity)
return FloorViewHolder(binding, adapter)
}
@SuppressLint("NotifyDataSetChanged", "SetTextI18n")
override fun onBindViewHolder(holder: FloorsAdapter.FloorViewHolder, position: Int) {
//For a given floor set the rooms on that floor's room adapter
val currentFloor = floorList[position]
holder.apply {
roomsAdapter.roomList(currentFloor.rooms)
binding.tvFloor.text = "Floor : ${currentFloor.floor}"
Timber.d("Rooms on floor: $currentFloor are : ${currentFloor.rooms}")
}
}
@SuppressLint("NotifyDataSetChanged")
fun floorList(floors: List<FloorsDataClass>) {
this.floorList = floors
notifyDataSetChanged()
}
override fun getItemCount(): Int {
return floorList.size
}
}
open class RoomsAdapter(
private val activity: FragmentActivity?
) : RecyclerView.Adapter<RoomsAdapter.RoomViewHolder>() {
private var roomList = emptyList<RoomsDataClass>()
inner class RoomViewHolder(
val binding: ListItemControlPanelRoomsBinding,
val machinesAdapter: DevicesAdapter
) : RecyclerView.ViewHolder(binding.root) {}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RoomViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val binding = ListItemControlPanelRoomsBinding.inflate(layoutInflater, parent, false)
//setting machines for each room
val adapter = DevicesAdapter()
binding.rvMachineControlPanel.adapter = adapter
binding.rvMachineControlPanel.layoutManager = LinearLayoutManager(activity)
return RoomViewHolder(binding, adapter)
}
@SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: RoomViewHolder, position: Int) {
val currentRoom = roomList[position]
Timber.d("Current room : $currentRoom")
holder.apply {
binding.tvRoom.text = "Room : ${currentRoom.room}"
machinesAdapter.devicesLists(currentRoom.devices)
}
}
@SuppressLint("NotifyDataSetChanged")
fun roomList(room: List<RoomsDataClass>) {
this.roomList = room
Timber.d("List received : $room")
notifyDataSetChanged()
}
override fun getItemCount(): Int {
return roomList.size
}
}
class DevicesAdapter : RecyclerView.Adapter<DevicesAdapter.MachinesViewHolder>() {
private var devicesList = emptyList<DevicesDataClass>()
inner class MachinesViewHolder(val binding: ListItemControlPanelMachinesBinding) :
RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MachinesViewHolder {
val inflater = LayoutInflater.from(parent.context)
val binding = ListItemControlPanelMachinesBinding.inflate(inflater, parent, false)
return MachinesViewHolder(binding)
}
override fun onBindViewHolder(holder: MachinesViewHolder, position: Int) {
val currentMachine = devicesList[position]
holder.apply {
binding.tvDevice.text = currentMachine.machine.toString()
}
}
override fun getItemCount(): Int {
return devicesList.size
}
fun devicesLists(machine: List<DevicesDataClass>) {
this.devicesList = machine
}
}
Edit 1:我需要片段数据为:
楼层 1 -> 房间 A -> 设备 1、设备 2 | RoomB -> 设备 3 || 2 楼 -> RoomC -> 设备、设备 5 | D室->设备,设备7
我得到的数据为:
Floor1 -> RoomA -> Device1、Device2、Device3、Device 4 ....(直到最后一个设备)| RoomBA -> 设备 1、设备 2、设备 3、设备 4 ....(直到最后一个设备)|| 2楼 -> 相同