如何使用分页库显示 RecyclerView 中列表数组中的每个项目

问题描述 投票:0回答:1

大家早上好,希望你们一切都好。 我正在使用带有两个表或实体的 Room 数据库,并希望使用分页库在回收器视图中显示学生所修读的所有课程的列表。在适配器的 bind() 方法中,当我第一次使用

binding.courseName.text = studentCourse.courses.courseName.toString()
在数据库中保存四门课程以及参加这些课程的学生的姓名后查看输出时,它返回一个如下数组:

**[课程(课程名称=Android,课程持续时间=50),课程(课程名称=Python,课程持续时间=40),课程(课程名称=Kotlin,课程持续时间=36),课程(课程名称=英语,课程持续时间=25)]

使用下面的代码,它在回收器视图中仅返回一门课程及其名称和持续时间,这是数组的最后一门课程。

两个表或实体CourseStudent定义如下:

@Entity(tableName = "course_table")
data class Course(
    @PrimaryKey(autoGenerate = false)
    val courseName : String,

    @ColumnInfo(name = "course_duration")
    val courseDuration : String
)
@Entity(tableName = "student_table")
data class Student(
    @PrimaryKey(autoGenerate = false)
    val studentName : String,

    val semester : Int,

    val schoolName : String
)

这两个类之间的关系由 StudentAndCourse 和 CourseAndStudent** 类表示,定义如下:

data class StudentAndCourse(
    @Embedded
    val student : Student,

    @Relation(
        parentColumn = "studentName",
        entityColumn = "courseName",
        associateBy = Junction(StudentAndCourseTogether::class)
    )

    val courses : List<Course>
)
data class CourseAndStudent(
    @Embedded
    val course : Course,

    @Relation(
        parentColumn = "courseName",
        entityColumn = "studentName",
        associateBy = Junction(StudentAndCourseTogether::class)
    )

    val students : List<Student>
)

我在 Dao 中定义的用于获取由其姓名标识的特定学生所修读的所有课程的查询是:

@Query("SELECT * FROM student_table WHERE studentName = :studentName")
    fun getAllCoursesByStudentName(studentName: String) : PagingSource<Int, StudentAndCourse>```


Here is my Paging Adapter class:

CourseByStudentNameAdapter 类: PagingDataAdapter(DiffCallback){

class CourseByStudentNameViewHolder(private val binding: CourseByStudentNameItemBinding) :
    RecyclerView.ViewHolder(binding.root){

    fun bind(studentAndCourse: StudentAndCourse){
        for (course in studentAndCourse.courses){
            binding.courseName.text = course.courseName
            binding.courseDuration.text = course.courseDuration
        }
    }
}

override fun onCreateViewHolder(
    parent: ViewGroup,
    viewType: Int,
): CourseByStudentNameAdapter.CourseByStudentNameViewHolder {
    val inflatedLayout = CourseByStudentNameItemBinding.inflate(LayoutInflater.from(
        parent.context), parent, false)

    return CourseByStudentNameViewHolder(inflatedLayout)
}


override fun onBindViewHolder(holder: CourseByStudentNameAdapter.CourseByStudentNameViewHolder, position: Int) {
    val currentCourse = getItem(position)

    if (currentCourse != null) {
        holder.bind(currentCourse)
    }
}



companion object DiffCallback : DiffUtil.ItemCallback<StudentAndCourse>(){
    override fun areItemsTheSame(
        oldItem: StudentAndCourse,
        newItem: StudentAndCourse
    ): Boolean = oldItem.courses == newItem.courses

    override fun areContentsTheSame(
        oldItem: StudentAndCourse,
        newItem: StudentAndCourse
    ): Boolean = oldItem == newItem

}

}```

我的包含项目的 XML 文件:

<androidx.constraintlayout.widget.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <androidx.appcompat.widget.LinearLayoutCompat
        android:id="@+id/linear_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:gravity="center"
        android:layout_marginTop="4dp"
        style="@style/itemListTextStyle"
        android:background="@drawable/item_layout_background"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent">

        <TextView
            android:id="@+id/course_name"
            android:layout_width="match_parent"
            tools:text="Computer"
            android:gravity="center"
            android:layout_height="wrap_content"/>

        <TextView
            android:id="@+id/course_duration"
            android:layout_width="match_parent"
            tools:text="15 hours"
            android:gravity="center"
            android:layout_height="wrap_content"/>

    </androidx.appcompat.widget.LinearLayoutCompat>

</androidx.constraintlayout.widget.ConstraintLayout>```



My fragment code:

```
@AndroidEntryPoint
class AllCourseByStudentNameFragment : Fragment() {

    private var _binding : FragmentAllCourseByStudentNameBinding? = null
    private val binding get() = _binding!!

    private val viewModel : SchoolViewModel by activityViewModels()

    private lateinit var adapter : CourseByStudentNameAdapter

    private val schoolName = "IFRI"
    private val studentName = "Esperant"
    private val courseName = "Android"

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setHasOptionsMenu(true)
    }


    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?,
    ): View? {
        // Inflate the layout for this fragment
        _binding = FragmentAllCourseByStudentNameBinding.inflate(inflater)
        return binding.root
    }

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

        adapter = CourseByStudentNameAdapter()
        binding.apply {
            recyclerView.adapter = adapter
            recyclerView.layoutManager = LinearLayoutManager(requireContext())
            recyclerView.setHasFixedSize(true)
        }

        viewModel.setName(studentName)
        viewModel.courseByStudentName.observe(viewLifecycleOwner){
            adapter.submitData(viewLifecycleOwner.lifecycle, it)
        }
    }

    override fun onDestroyView() {
        super.onDestroyView()

        _binding = null
    }
}```

I will be very glad to get your help. Thanks in advance.




android android-room android-paging-library
1个回答
0
投票

问题出在您的 ViewHolder 上。 ViewHolder 代表 RecyclerView 中的单个项目,而不是全部。

您实施的方式:

class CourseByStudentNameViewHolder(private val binding: CourseByStudentNameItemBinding) :
    RecyclerView.ViewHolder(binding.root){

    fun bind(studentAndCourse: StudentAndCourse){
        for (course in studentAndCourse.courses){
            binding.courseName.text = course.courseName
            binding.courseDuration.text = course.courseDuration
        }
    }
}

当您传递 StudentAndCourse 项目(这是单个项目)时,您的适配器会认为只有 1 个项目可显示。您的 ViewHolder 应该用于绑定单个 RecyclerView 项目(课程)的数据。您实现它的方式是循环遍历所有课程,并且对于每个循环,您都会再次覆盖 courseName 和 courseDuration。因此,最终只有最后一门课程的值可见,因为之前的所有课程都被覆盖。

不要在适配器中使用 StudentAndCourse,而是尝试在 StudentAndCourse 对象中为每门课程传递一个课程,这样适配器就知道列表中有多于 1 个项目。

class CourseByStudentNameAdapter : PagingDataAdapter<Course, CourseByStudentNameAdapter.CourseByStudentNameViewHolder>(DiffCallback) {

    class CourseByStudentNameViewHolder(private val binding: CourseByStudentNameItemBinding) : RecyclerView.ViewHolder(binding.root){
    
        fun bind(course: Course){
            binding.courseName.text = course.courseName
            binding.courseDuration.text = course.courseDuration
        }
    }

    override fun onCreateViewHolder(
        parent: ViewGroup,
        viewType: Int,
    ): CourseByStudentNameAdapter.CourseByStudentNameViewHolder {
        val inflatedLayout = CourseByStudentNameItemBinding.inflate(LayoutInflater.from(
            parent.context), parent, false)

        return CourseByStudentNameViewHolder(inflatedLayout)
    }


    override fun onBindViewHolder(holder: CourseByStudentNameAdapter.CourseByStudentNameViewHolder, position: Int) {
        val currentCourse = getItem(position)

        if (currentCourse != null) {
            holder.bind(currentCourse)
        }
    }


    companion object DiffCallback : DiffUtil.ItemCallback<Course>(){
        override fun areItemsTheSame(
            oldItem: Course,
            newItem: Course
        ): Boolean = oldItem.courseName == newItem.courseName

        override fun areContentsTheSame(
            oldItem: Course,
            newItem: Course
        ): Boolean = oldItem == newItem

    }
}

分页数据可以看一下官方文档:Documentation

© www.soinside.com 2019 - 2024. All rights reserved.