大家早上好,希望你们一切都好。 我正在使用带有两个表或实体的 Room 数据库,并希望使用分页库在回收器视图中显示学生所修读的所有课程的列表。在适配器的 bind() 方法中,当我第一次使用
binding.courseName.text = studentCourse.courses.courseName.toString()
在数据库中保存四门课程以及参加这些课程的学生的姓名后查看输出时,它返回一个如下数组:
**[课程(课程名称=Android,课程持续时间=50),课程(课程名称=Python,课程持续时间=40),课程(课程名称=Kotlin,课程持续时间=36),课程(课程名称=英语,课程持续时间=25)]
使用下面的代码,它在回收器视图中仅返回一门课程及其名称和持续时间,这是数组的最后一门课程。
两个表或实体Course和Student定义如下:
@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
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.
问题出在您的 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