在 Android 中处理多个回收器视图 [Kotlin]

2024-05-06

我遇到过这样的情况:一个布局上有 3 个 RecyclerView。他们以某种方式相互依赖。数据来自房间数据库。

问题原型(问题陈述):假设您有类似(Floor1、Floor2、Floor3 等)的楼层,并且每个楼层内都有类似(Room1、Room2、Room3 等)的房间,并且每个房间内都有姓名类似(PersonA、PersonB、PersonC)的人。 给定的约束是:一个人不能在同一类型的两个不同房间中。

Edit 1:楼层、房间和人员以字符串列表的形式来自数据库。

您将如何使用(回收器视图)或单个屏幕布局上的任何内容来显示这一点。楼层、房间和人员的数量可以是无限的。但该信息是从房间数据库中获取的。

我的方法:(这不是一个完整的方法),但我想在顶部有一个 RecyclerView 来容纳一定数量的楼层。我们使用查询从数据库中获取总楼层并对它们进行排序并显示。在此期间onBindViewHolder()在楼层适配器中,我们有一个条件,检查是否有与该楼层关联的房间,如果有,则我们进行另一个查询以从数据库中获取并显示它(可能使用新的回收器视图),但我不知道怎么做。嵌套回收器视图是可以在这里使用的东西吗?

它并没有就此停止,因为我们使用该房间名称对数据库进行另一个查询以查找该房间内的所有人员。这是回收者的另一个观点。 我正在考虑应用这种方法,但我觉得实施这种方法有很多阻碍。我不确定这是否是处理此类事情的方法。

Image for reference : Image

我正在寻找任何信息,如果您遇到过此类情况,那么您采取了什么方法。是否有任何库可用于简化此任务,或者您可以提供的任何知识都会有所帮助。谢谢!

Edit 2:现在正在做什么: 我尝试实现嵌套回收器视图。事情似乎工作正常,因为现在我有两个适配器(用于地板和房间),我正在从片段中充气地板适配器,并从片段中充气房间适配器onBindViewHolder地板适配器。

我现在面临的问题是,在回收器视图内,我正确地获取了楼层列表,但对于房间列表(在子回收器视图中),我只获取了最后一层的列表。

Check this image for reference (Floor 2 and 1 also have rooms but I am only getting room C1 which is present in last floor which is 3) : Image2

适配器中的当前代码:

class FloorsAdapter(
    private val controlPanelViewModel: ControlPanelViewModel,
    private val activity: FragmentActivity?
) : RecyclerView.Adapter<FloorsAdapter.FloorViewHolder>() {

    private var floorList = emptyList<String>()

    private lateinit var roomAdapter: RoomAdapter

    inner class FloorViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {}

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

    override fun onBindViewHolder(holder: FloorsAdapter.FloorViewHolder, position: Int) {
        val item = floorList[position]
        ListItemControlPanelFloorsBinding.bind(holder.itemView).apply {
            Timber.d("Current floor is $item, Floor List is : $floorList")
            tvFloor.text = item

            roomAdapter = RoomAdapter(controlPanelViewModel, activity)
            rvRoomControlPanel.adapter = roomAdapter
            rvRoomControlPanel.layoutManager = LinearLayoutManager(activity)

            controlPanelViewModel.getAllRooms(item).observeForever(Observer {
                Timber.d("List of rooms : $it")

                //Finding distinct rooms
                val distinct = it.toSet().toList()
                Timber.d("Distinct rooms list : $distinct")
                roomAdapter.roomList(distinct)
            })
        }
    }

    @SuppressLint("NotifyDataSetChanged")
    fun floorList(floors: List<String>) {
        this.floorList = floors
        notifyDataSetChanged()
    }

    override fun getItemCount(): Int {
        return floorList.size
    }
}

class RoomAdapter(
    private val controlPanelViewModel: ControlPanelViewModel,
    private val activity: FragmentActivity?
) : RecyclerView.Adapter<RoomAdapter.RoomViewHolder>() {

    private var roomList = emptyList<String>()

    inner class RoomViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {}

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

    override fun onBindViewHolder(holder: RoomViewHolder, position: Int) {
        val item = roomList[position]
        ListItemControlPanelRoomsBinding.bind(holder.itemView).apply {
            Timber.d("Current room is $item")
            tvRoom.text = item
        }
    }

    @SuppressLint("NotifyDataSetChanged")
    fun roomList(room: List<String>) {
        this.roomList = room
        notifyDataSetChanged()
    }

    override fun getItemCount(): Int {
        return roomList.size
    }

}

片段中用于充气地板适配器的代码:

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

        binding.rvFloors.adapter = adapter
        binding.rvFloors.layoutManager = LinearLayoutManager(requireContext())

        controlPanelViewModel.getAllFloors.observe(viewLifecycleOwner, Observer{
            Timber.d("List is $it")
            //Remove duplicates from received list
            val distinct = it.toSet().toList()
            Timber.d("List after removing duplicates: $distinct")
            adapter.floorList(distinct)
        })
        Timber.d("Adapter: $adapter" )
    }

Edit 3:通过查看日志,我发现了一些可以解释为什么会发生这种情况的内容。因此,楼层列表首先被执行

controlPanelViewModel.getAllFloors.observe(viewLifecycleOwner, Observer{
            Timber.d("List is $it")
            //Remove duplicates from received list
            val distinct = it.toSet().toList()
            Timber.d("List after removing duplicates: $distinct")
            adapter.floorList(distinct)
        })

当我们正在膨胀房间回收者从地板适配器的视图时

  roomAdapter = RoomAdapter(controlPanelViewModel, activity)
            rvRoomControlPanel.adapter = roomAdapter
            rvRoomControlPanel.layoutManager = LinearLayoutManager(activity)

            controlPanelViewModel.getAllRooms(item).observeForever(Observer {
                Timber.d("List of rooms : $it")

                //Finding distinct rooms
                val distinct = it.toSet().toList()
                Timber.d("Distinct rooms list : $distinct")
                roomAdapter.roomList(distinct)
            })

当从 Room 获取数据时,会有一点延迟。所以不要做类似的事情(Floor 1 -> Room1, Room2我们得到类似的东西(Floor1, Floor2 -> Room3, Room4)。有关先前楼层房间的数据正在丢失。

在这里做什么?除非我们已获取所有房间并使用文本视图显示,否则如何停止下一层的执行。


我尝试使用一个垂直回收器视图和水平回收器视图来复制确切的场景。事情是这样的,一个垂直的楼层回收器视图。然后,可以将楼层项目中的房间项目视图列表添加到垂直线性布局容器中。单个房间项目视图包含人员的水平回收器视图。

地板垂直 RV -> 将自定义房间项目添加到垂直 LL -> 人员 卧式房车

Hope it helps. enter image description here

活动:

class MainActivity : AppCompatActivity() {
    private lateinit var recyclerView: RecyclerView
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        recyclerView = findViewById(R.id.mainRv)
        recyclerView.apply {
            adapter = FloorAdapter(getFloors(), this@MainActivity)
            layoutManager = LinearLayoutManager(this@MainActivity)
            setHasFixedSize(true)
            addItemDecoration(DividerItemDecoration(context, DividerItemDecoration.VERTICAL))
        }
    }

    fun getFloors(): List<Floor> {
        val list = ArrayList<Floor>()
        for (i in 0 until 6) {
            list.add(Floor())
        }
        return list
    }
}
    
    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    
        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/mainRv"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    
    </androidx.constraintlayout.widget.ConstraintLayout>

适配器:

class FloorAdapter(val floors: List<Floor>, val context:Context) : RecyclerView.Adapter<FloorViewHolder>() {
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FloorViewHolder {
        return FloorViewHolder(LayoutInflater.from(context).inflate(R.layout.floor_item,null))
    }

    override fun onBindViewHolder(holder: FloorViewHolder, position: Int) {
        holder.bindView(floors[position])
    }

    override fun getItemCount(): Int {
        return floors.size
    }

}

class PersonAdapter(val persons: List<Person>, val context:Context) : RecyclerView.Adapter<PersonViewHolder>() {
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PersonViewHolder {
        return PersonViewHolder(LayoutInflater.from(context).inflate(R.layout.person_item,null))
    }

    override fun onBindViewHolder(holder: PersonViewHolder, position: Int) {
        holder.bindView(persons[position])
    }

    override fun getItemCount(): Int {
        return persons.size
    }

}

查看持有者:

class PersonViewHolder(val view:View) : RecyclerView.ViewHolder(view) {
    fun bindView(person: Person) {
        view.findViewById<TextView>(R.id.person_tv).text = "Person:${person.personId}"
    }
}

class FloorViewHolder(val view:View) : RecyclerView.ViewHolder(view){
    fun bindView(floor: Floor){
        val str =  "Floor : ${floor.floorId}"
        view.findViewById<TextView>(R.id.floor).text = str
        view.findViewById<LinearLayout>(R.id.room_container).let { ll->
            ll.removeAllViews()
            floor.rooms.forEach{
                val myView= LayoutInflater.from(view.context).inflate(R.layout.room_item,null)
                myView.findViewById<TextView>(R.id.room).text = "RoomId :${it.roomId}"
  

                  myView.findViewById<RecyclerView>(R.id.persons_rv)?.apply {
                        adapter = PersonAdapter(it.persons,view.context)
                        layoutManager = LinearLayoutManager(view.context,LinearLayoutManager.HORIZONTAL,false)
                        setHasFixedSize(true)
                    }
                    ll.addView(myView)
                }
            }
        }
    }

数据类别:

       data class Floor(val floorId: Int = (0..900).random()) {
        var rooms = arrayListOf<Room>()
        init {
            for (i in 0 until 50) {
                rooms.add(Room())
            }
        }
    }
 data class Room(val roomId: Int = (0..900).random()) {
        var persons = arrayListOf<Person>()
        init {
            for (i in 0 until 200) {
                persons.add(Person())
            }
        }
    }
    data class Person(val personId: Int = (0..900).random())

Floor_item.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/floor"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="22sp"
        android:textStyle="bold"
        android:textColor="@android:color/holo_red_dark"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <LinearLayout
        android:id="@+id/room_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:orientation="vertical"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/floor"
        />
</androidx.constraintlayout.widget.ConstraintLayout>

person_item.xml

<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.textview.MaterialTextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:padding="18dp"
    android:id="@+id/person_tv"
    android:textSize="18sp"
    android:layout_margin="10dp"
    android:background="@android:color/holo_blue_light"
    android:textColor="@color/black"
    android:layout_height="wrap_content">

</com.google.android.material.textview.MaterialTextView>

room_item.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:padding="20dp"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/room"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="@android:color/holo_green_dark"
        android:textSize="18sp"
        android:textStyle="bold"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/persons_rv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        app:layout_constraintTop_toBottomOf="@id/room" />
</androidx.constraintlayout.widget.ConstraintLayout>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 Android 中处理多个回收器视图 [Kotlin] 的相关文章

随机推荐

  • 需要对 mongodb 中的数组对象值求和

    如果该值存在 我正在尝试计算总价值 但查询并不能 100 工作 那么有人可以帮我解决这个问题吗 这是我的示例文档 我附上了两份文件 请提供这些文件并找出最佳解决方案 文件 1 id 1 message count 4 messages da
  • MPMoviePlayerController 添加自定义播放按钮

    目前我正在开发一个显示视频的 iPhone 应用程序 我使用 MPMoviePlayerController 从本地文件夹加载视频 我们可以定制标准媒体播放器吗 我想要做的是隐藏所有标准元素 播放 前进 倒带 完成 并仅使用带有自定义图像的
  • 包 javax.comm 不存在[重复]

    这个问题在这里已经有答案了 可能的重复 如何获取javax comm API https stackoverflow com questions 7562565 how to get javax comm api 我已经下载并安装了jdk1
  • 无法安装组件:模板或渲染函数未定义。组件导入失败

    我正在尝试复制 vue 教程示例 在这里找到 https v3 vuejs org guide component basics html passing data to child components with props https
  • Sails.js 中的子域路由

    我试图找出一种在 Sails js 中以完全动态的方式路由子域的方法 默认路由似乎不允许这样做 例如 如果用户访问 yourname example com 则路由会将其读取为 example com users theirname 并且子
  • 应用程序注册失败,因为文件位于网络共享上。注册包之前将文件复制到本地计算机

    我使用这些示例来构建 Windows 8 应用程序 http code msdn microsoft com windowsapps Getting started with C and 41e15af5 http code msdn mi
  • 在 HTML 中设置 LI 标记的值

    我有一个有序列表 我需要为其设置 值 就像是 ol li apple li li pear li li car li ol 这样它们就会显示我分配的数字 34 apple 45 pear 55 car 有没有办法告诉 LI 应显示什么数字
  • 无法使用服务帐户查询 Google Search Console API

    我需要使用服务帐户从 Google Search Console 网站管理员工具 检索一些数据 到目前为止我已经能够检索到access token对于我需要附加到请求的 url 的服务帐户 问题是我找不到办法这样做 这是我正在使用的代码 f
  • C# 和泛型 - 为什么调用基类中的方法而不是派生类中的新方法?

    如果泛型类型参数 调用类或调用方法的 受以下约束where T Base不会调用 T Derived 中的新方法 而是调用 Base 中的方法 为什么类型 T 在方法调用中被忽略 即使它应该在运行时之前已知 Update 但是 当约束使用像
  • 自定义字体,eot,不起作用

    我无法让我的自定义字体在 IE7 和 IE8 中工作 http i creative dk iJob http i creative dk iJob 它在 IE9 Firefox 和 Chrome 中运行良好 对于 Firefox 和 Ch
  • 每当调用 malloc/free 时输出到 stderr

    使用 Linux GCC C 每当调用 malloc free new delete 时 我想向 stderr 记录一些内容 我试图了解库的内存分配 因此我想在运行单元测试时生成此输出 我使用 valgrind 进行内存泄漏检测 但我找不到
  • 我的 rtk 切片的初始状态未按预期保存在存储中?

    目前正在学习如何将 RTK 与 typescript 结合使用 我有 2 个切片 其中一个是我使用 RTK 查询制作的以获取数据 称为apiSlice ts 另一个使用 createSlice 来处理我的待办事项应用程序的同步状态更改 称为
  • 在 MATLAB 中将数据拟合到 B 样条

    我正在尝试估计矩阵形式的时间序列数据中的缺失值 列代表时间点 即现在 我想将矩阵的每一行拟合到 B 样条曲线 并用它来估计缺失值 我可以使用 MATLAB 将数据拟合到普通样条曲线 但我完全陷入尝试找出如何拟合数据以创建 B 样条曲线的困境
  • Android:如何获取设备的真实屏幕尺寸?

    我尝试了不同的方法来获取设备的屏幕尺寸 但它总是返回错误的尺寸 791x480代替854x480 可能是导航栏的原因 我的设备当前运行的是 JellyBean 4 1 1 I tried Display display getWindowM
  • OSGI - 处理捆绑包所需的第 3 方 JAR

    我刚刚开始 OSGI 开发 正在努力了解如何最好地处理依赖的 JAR 也就是说 如果我要创建一个捆绑包 我很可能需要使用一些第 3 方 JAR 当我创建要部署到 OSGI 的捆绑包 JAR 时 显然不包含这些第 3 方 JAR 因此该捆绑包
  • event.getSource() 返回 null android 中的可访问性

    我尝试使用 DashLane 等辅助服务或其他一些使用辅助服务的应用程序来填充 EditText 字段 我正在使用聚焦事件视图 当 EditText 获得焦点时 事件开始但是getSource 返回空值 Code Accessibility
  • 奇怪的 JavaCore IType 缓存问题

    我正在开发一个插件 它接受工作区中实现某些接口 IDomain 的所有枚举 解析代码 使用 AST 对枚举进行一些修改 并将其标记为使用注释 IDomainInfo 进行处理 例如 它需要这样的东西 public enum SomeEnum
  • conda 环境中 conda 和 pip 安装的区别

    我似乎经常问自己这个问题 最近改用 conda 环境 Anaconda 但我最终用谷歌搜索并没有走得太远 我现在在自己的 conda 环境中运行所有项目 因为我喜欢将所有内容保持独立 并尽可能减少对其他程序的依赖 比如最近的一个环境 con
  • Facebook Analytics:使用图形 API 的用户属性和记录事件

    我有 facebook 应用程序 Messenger Bot 应用程序 我使用图形 API 端点记录每个用户的自定义事件 申请 活动 事件被完美记录 我想要做的是为我的信使机器人用户创建自定义属性 以便我可以使用此属性对应用程序数据进行分段
  • 在 Android 中处理多个回收器视图 [Kotlin]

    我遇到过这样的情况 一个布局上有 3 个 RecyclerView 他们以某种方式相互依赖 数据来自房间数据库 问题原型 问题陈述 假设您有类似 Floor1 Floor2 Floor3 等 的楼层 并且每个楼层内都有类似 Room1 Ro