Reputation: 3
Employee class:
data class Employee(
val id: Long,
val fullName: String,
val city: String,
var isLiked: Boolean = false,
) {
companion object {
fun getMockEmployees() = listOf(
Employee(
0,
"John Johnson",
"London",
),
Employee(
1,
"John Johnson",
"London",
),
Employee(
2,
"John Johnson",
"London",
),
Employee(
3,
"John Johnson",
"London",
)
)
}
EmployeeAdapter:
class EmployeeAdapter(
private val clickedLike: (Int) -> Unit
) :
RecyclerView.Adapter<EmployeeAdapter.EmployeeViewHolder>() {
private val employees = mutableListOf<Employee>()
inner class EmployeeViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val employeeCard: ConstraintLayout = itemView.findViewById(R.id.employees_list_item)
val fullNameTextView: TextView = itemView.findViewById(R.id.full_name)
val likeButton: ImageView = itemView.findViewById(R.id.like_button)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): EmployeeViewHolder {
val view =
LayoutInflater.from(parent.context).inflate(R.layout.employees_list_item, parent, false)
return EmployeeViewHolder(view)
}
override fun onBindViewHolder(holder: EmployeeViewHolder, position: Int) {
val employee = employees[position]
with(holder) {
fullNameTextView.text = employee.fullName
likeButton.visibility = if (employee.isLiked) View.VISIBLE else View.INVISIBLE
employeeCard.setOnClickListener {
clickedLike(position)
likeButton.visibility = if (employee.isLiked) View.VISIBLE else View.INVISIBLE
}
}
}
override fun getItemCount(): Int {
return employees.size
}
fun reload(data: List<Employee>) {
val diffUtil = EmployeesDiffUtilCallback(employees, data)
val result = DiffUtil.calculateDiff(diffUtil)
employees.clear()
employees.addAll(data)
result.dispatchUpdatesTo(this)
}
EmployeesDiffUtilCallback:
class EmployeesDiffUtilCallback(
private val oldList: List<Employee>,
private val newList: List<Employee>
) : DiffUtil.Callback() {
override fun getOldListSize() = oldList.size
override fun getNewListSize() = newList.size
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldList[oldItemPosition].id == newList[oldItemPosition].id
}
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
val old = oldList[oldItemPosition]
val new = newList[oldItemPosition]
return old.id == new.id && (old.isLiked == new.isLiked)
}
}
MainActivity:
private val viewModel: MainActivityViewModel by viewModels()
private lateinit var employeeAdapter: EmployeeAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val recyclerView = findViewById<RecyclerView>(R.id.recycler_view)
recyclerView.layoutManager = GridLayoutManager(this, 2)
val itemDecoration = DividerItemDecoration(
recyclerView.context,
GridLayoutManager.VERTICAL
)
val itemDecoration2 = DividerItemDecoration(
recyclerView.context,
GridLayoutManager.HORIZONTAL
)
recyclerView.addItemDecoration(itemDecoration)
recyclerView.addItemDecoration(itemDecoration2)
employeeAdapter = EmployeeAdapter(viewModel::likeEmployee)
recyclerView.adapter = employeeAdapter
viewModel.employees.observe(this) {
employeeAdapter.reload(it)
}
}
MainActivityViewModel :
val employees = MutableLiveData(Employee.getMockEmployees())
fun likeEmployee(position: Int) {
employees.value?.get(position)?.isLiked = !(employees.value?.get(position)?.isLiked)!!
}
My mentor have said that modification of flag Employee::isLiked should be in ViewModel and after it by using LiveData ViewModel it should tell UI about changes in list. I'm new in Kotlin and don't understand how to do it. Help me pls
Upvotes: 0
Views: 174
Reputation: 589
I think you have a good basis for your use case and what your mentor wants.
You can improve and simplify your Adapter by using a ListAdapter with DiffCallback:
class EmployeeAdapter(
private val onEmployeeLiked: (Employee) -> Unit
) : ListAdapter<Employee, EmployeeAdapter.EmployeeViewHolder>(DiffCallback()){
inner class EmployeeViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val employeeCard: ConstraintLayout = itemView.findViewById(R.id.employees_list_item)
val fullNameTextView: TextView = itemView.findViewById(R.id.full_name)
val likeButton: ImageView = itemView.findViewById(R.id.like_button)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): EmployeeViewHolder {
val view =
LayoutInflater.from(parent.context).inflate(R.layout.employees_list_item, parent, false)
return EmployeeViewHolder(view)
}
override fun onBindViewHolder(holder: EmployeeViewHolder, position: Int) {
val employee = employees[position]
with(holder) {
fullNameTextView.text = employee.fullName
likeButton.visibility = if (employee.isLiked) View.VISIBLE else View.INVISIBLE
employeeCard.setOnClickListener {
onEmployeeLiked(employee)
likeButton.isVisible = employee.isLiked
}
}
}
}
class DiffCallback : DiffUtil.ItemCallback<Employee>() {
override fun areItemsTheSame(
oldItem: Employee,
newItem: Employee
): Boolean = // use id or other identifier to determine if employees are the same
override fun areContentsTheSame(
oldItem: Employee,
newItem: Employee
): Boolean = // compare empty
}
With a ListAdapter
, you do not have to manage updating your list by yourself. Just use adapter.submitList(list)
and the adapter will update itself.
You can use isVisible
on the View
class to update the visibility more easily.
I would also give the Employee
in the callback, then you do not have to get it again.
class MainActivityViewModel{
val employees = MutableLiveData(Employee.getMockEmployees())
fun onEmployeeLiked(employee : Employee){
val currentEmployees = employee.value?.toMutableList()?: return
val index = currentEmployees.indexOf{ e -> e.id == employee.id} //find the index of the updated employee
if(index == -1) return // employee not found
employee.isLiked = !employee.isLiked
currentEmployees.set(index, employee) // update employee in list
employees.value = currentEmployees // set new value
}
}
// Activity
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val recyclerView = findViewById<RecyclerView>(R.id.recycler_view)
recyclerView.layoutManager = GridLayoutManager(this, 2)
val itemDecoration = DividerItemDecoration(
recyclerView.context,
GridLayoutManager.VERTICAL
)
val itemDecoration2 = DividerItemDecoration(
recyclerView.context,
GridLayoutManager.HORIZONTAL
)
recyclerView.addItemDecoration(itemDecoration)
recyclerView.addItemDecoration(itemDecoration2)
employeeAdapter = EmployeeAdapter(viewModel::likeEmployee)
recyclerView.adapter = employeeAdapter
viewModel.employees.observe(this) { employees ->
employeeAdapter.submitList(employees) // display the updated list in the adapter
}
}
Upvotes: 0