Good morning everyone, I hope you're doing great.
I'm working with Room database with two tables or entities and want to display the list of all courses taken by a student in a recycler View using paging librar. In bind() method of the adapter, when I first used binding.courseName.text = studentCourse.courses.courseName.toString()
to see the output after saving four courses in the Database and the name of a student who has taken these courses, it returns an array like this:
**[Course(courseName=Android, courseDuration=50), Course(courseName=Python, courseDuration=40), Course(courseName=Kotlin, courseDuration=36), Course(courseName=English, courseDuration=25)]
With the code below, it returns only one course with its name and duration in the recycler view and that is the last course of the array .
The two tables or entities Course and Student are defined like this:
@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
)
The relations between these two classes are represented by StudentAndCourse and CourseAndStudent** classes defined like:
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>
)
The query I defined in Dao to get all courses taken by a specific student identified by his name is :
@Query("SELECT * FROM student_table WHERE studentName = :studentName")
fun getAllCoursesByStudentName(studentName: String) : PagingSource<Int, StudentAndCourse>```
Here is my Paging Adapter class:
class CourseByStudentNameAdapter : PagingDataAdapter<StudentAndCourse, CourseByStudentNameAdapter.CourseByStudentNameViewHolder>(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
}
}```
My XML file that holds items:
<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.