In my application I want use recyclerview with DiffUtils into recyclerview adapter.
When I scroll between the items, the items get messed up and moved.
I should added this code holder.setIsRecyclable(false)
into onBindViewHolder to fix this problem!
But I don't want disable recyclerview mode!
My codes:
class ReservedListAdapter @Inject constructor() : RecyclerView.Adapter<ReservedListAdapter.ViewHolder>() {
private lateinit var binding: ItemReservedListBinding
private lateinit var context: Context
private var moviesList = emptyList<Result>()
private val userToken by lazy { GoodPrefs.getInstance().getString(USER_TOKEN, "") }
private var selectedType = ""
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
binding = ItemReservedListBinding.inflate(LayoutInflater.from(parent.context), parent, false)
context = parent.context
return ViewHolder()
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(moviesList[position])
holder.setIsRecyclable(false)
}
override fun getItemCount() = moviesList.size
//override fun getItemId(position: Int) = position.toLong()
inner class ViewHolder : RecyclerView.ViewHolder(binding.root) {
@SuppressLint("SetTextI18n", "NotifyDataSetChanged", "CheckResult")
fun bind(item: Result) {
binding.apply {
//Title
var type = ""
item.counseling?.let { counseling ->
type = if (counseling.type == PHONE) {
context.getString(R.string.byPhone)
} else {
context.getString(R.string.textual)
}
titleTxt.text = "${context.getString(R.string.visit)} $type - " +
context.getString(R.string.doctor) +
"${counseling.physician?.firstName} ${counseling.physician?.lastName}"
}
//Date
if (item.startAt != null) {
val date = item.startAt.split(" ")[0]
val hour = item.startAt.split(" ")[1]
val showDate = if (item.counseling?.type == PHONE) {
"${date.convertDateToFarsiWithMonthName()} | " + "${context.getString(R.string.hour)} ${hour.dropLast(3)}"
} else {
"${date.convertDateToFarsiWithMonthName()} | ${context.getString(R.string.duringDay)}"
}
dateTxt.text = showDate
}
//Avatar
if (item.counseling?.physician?.profile?.files != null) {
if (item.counseling.physician.profile.files.isNotEmpty()) {
item.counseling.physician.profile.files.forEach { file ->
if (file?.description == AVATAR) {
avatarLoading.visibility = View.VISIBLE
ApiClient.getInstance().apisUseCase().getAvatarImage(userToken, file.id!!)
.applyIoScheduler()
.subscribe({
avatarLoading.visibility = View.GONE
if (it.isSuccessful) {
if (it.code() == 200) {
if (it.body() != null) {
val decodedBytes: ByteArray =
Base64.decode(it.body()!!.data!!.file, Base64.DEFAULT)
avatarImg.load(decodedBytes)
}
}
}
}, {
avatarLoading.visibility = View.GONE
})
} else {
avatarImg.load(R.drawable.avatar_doctor)
}
}
}
}
//Status
infoTxt.text = item.status
infoTxt.setCorner(10)
//Click
binding.root.setOnClickListener {
notifyDataSetChanged()
onItemClickListener?.let {
it(item, selectedType)
}
}
}
}
}
private fun dynamicallyStatusColor(textColor: Int, bgColor: Int) {
binding.infoTxt.apply {
setTextColor(ContextCompat.getColor(context, textColor))
setBgColor(ContextCompat.getColor(context, bgColor))
}
}
private var onItemClickListener: ((Result, String) -> Unit)? = null
fun setOnItemClickListener(listener: (Result, String) -> Unit) {
onItemClickListener = listener
}
fun setData(data: List<Result>) {
val moviesDiffUtil = BaseDiffUtils(moviesList, data)
val diffUtils = DiffUtil.calculateDiff(moviesDiffUtil)
moviesList = data
diffUtils.dispatchUpdatesTo(this)
}
}
BaseDiffUtils codes:
class BaseDiffUtils<T>(private val oldItem: List<T>, private val newItem: List<T>) : DiffUtil.Callback() {
override fun getOldListSize(): Int {
return oldItem.size
}
override fun getNewListSize(): Int {
return newItem.size
}
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldItem[oldItemPosition] === newItem[newItemPosition]
}
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldItem[oldItemPosition] === newItem[newItemPosition]
}
}
我如何解决这个问题?