DiffUtil areContentsTheSame() always returns true, after the contents are updated of the List in RecycleViewAdapter - android-recyclerview

This is my RecyclerView Adapter Class. Clicking an item from the list UI should change of the particular item like background black to white. After clicking an item I am changing the status of the item 0 to 1 from the UI class, based on that status UI should change of the item. But inside diffUtil areContentTheSame() retures true.
class TimeSlotsAdapter(val adapterItemOnClick: (TimeSlots) -> Unit):RecyclerView.Adapter<TimeSlotsAdapter.TimeSlotsViewHolder>() {
private lateinit var binding: RvTimeSlotsBinding
private var timeSlots: List<TimeSlots> = ArrayList<TimeSlots>()
inner class TimeSlotsViewHolder : RecyclerView.ViewHolder {
constructor(rvBinding: RvTimeSlotsBinding) : super(rvBinding.root) {
}
fun setItem(timeSlots: TimeSlots) {
binding.timeSlotView.setOnClickListener { adapterItemOnClick(timeSlots) }
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TimeSlotsViewHolder {
binding =
RvTimeSlotsBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return TimeSlotsViewHolder(binding)
}
override fun onBindViewHolder(holder: TimeSlotsViewHolder, position: Int) {
timeSlots[position]?.let { currentSlot ->
with(holder) {
if (currentSlot.status == "1") {
binding.timeSlotView.background =
ContextCompat.getDrawable(
binding.timeSlotView.context,
R.drawable.time_slot_item_bg
)
binding.timeSlotTv.setTextColor(
ContextCompat
.getColor(binding.timeSlotTv.context, R.color.black)
)
binding.timeSlotTv.text = "1 " + currentSlot.time
Timber.e("${currentSlot.time} ${currentSlot.status}")
} else {
binding.timeSlotView.background =
ContextCompat.getDrawable(
binding.timeSlotView.context,
R.drawable.black_bg
)
binding.timeSlotTv.setTextColor(
ContextCompat
.getColor(binding.timeSlotTv.context, R.color.white)
)
binding.timeSlotTv.text = "0 " + currentSlot.time
Timber.e("${currentSlot.time} ${currentSlot.status}")
}
setItem(currentSlot)
}
}
}
override fun getItemCount(): Int = timeSlots.size
fun submitSlots(timeSlotList: List<TimeSlots>) {
val oldList = timeSlots
val diffResult: DiffUtil.DiffResult = DiffUtil.calculateDiff(
TimeSlotsDiffCallBack(
oldList,
timeSlotList
)
)
timeSlots = timeSlotList
diffResult.dispatchUpdatesTo(this)
}
class TimeSlotsDiffCallBack(
var oldTimeSlotsList: List<TimeSlots>,
var newTimeSlotsList: List<TimeSlots>
) : DiffUtil.Callback() {
override fun getOldListSize(): Int = oldTimeSlotsList.size
override fun getNewListSize(): Int = newTimeSlotsList.size
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return (oldTimeSlotsList[oldItemPosition].time
== newTimeSlotsList[newItemPosition].time)
}
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
val oldTimeSlots = oldTimeSlotsList[oldItemPosition].status
val newTimeSlots = newTimeSlotsList[newItemPosition].status
Timber.e("old: $oldTimeSlots new: $newTimeSlots")
return oldTimeSlots == newTimeSlots
}
}
}
This is the UI class for submitting adapter list. Below the doClickTimeSlot() I am updating the status of the items.
class TimeSlotBottomSheetFragment : BottomSheetDialogFragment(){
private val obj: List<TimeSlots> = mutableListOf<TimeSlots>(
TimeSlots("09:30", "0"),
TimeSlots("10:30", "0"),
TimeSlots("11:30", "0"),
TimeSlots("12:30", "0"),
TimeSlots("14:30", "0"),
TimeSlots("15:30", "0"),
TimeSlots("16:30", "0"),
TimeSlots("17:30", "0"),
TimeSlots("18:30", "0"),
TimeSlots("19:30", "0"),
TimeSlots("20:30", "0"),
TimeSlots("21:30", "0")
)
private fun doClickTimeSlot(timeSlots: TimeSlots) {
val newList: ArrayList<TimeSlots> = ArrayList<TimeSlots>()
newList.addAll(obj)
for (i in newList.indices) {
if (newList[i].time == timeSlots.time) {
newList[i].status = "1"
Timber.e("" + newList[i].time + " " + newList[i].status)
} else {
newList[i].status = "0"
Timber.e("" + newList[i].time + " " + newList[i].status)
}
}
adapter.submitSlots(newList)
}
}

Related

how do i update items that change in recyclerview use diffutil?

DiffUtil do not update items recyclerview with the same id and not same the content,
The model has [id : Int and title : String]. I want to the diffUtilCallBack check items with the same id and not same title and update to recyclerview
Please help me fix it
my DiffUtil CallBAck
class DiffCB(
val oldl : ArrayList<Test>,
val newl : ArrayList<Test>
) : DiffUtil.Callback() {
override fun getOldListSize(): Int {
return oldl.size
}
override fun getNewListSize(): Int {
return newl.size
}
override fun areItemsTheSame(oldItemPos: Int, newItemPos: Int): Boolean {
return oldl[oldItemPos].id == newl[newItemPos].id
}
override fun areContentsTheSame(oldItemPos: Int, newItemPos: Int): Boolean {
return oldl[oldItemPos].title.equals(newl[newItemPos].title)
}
}
my Adapter.kt
class TestAdapter(val click: TestClick) :
RecyclerView.Adapter<TestAdapter.TestVH>() {
var list: ArrayList<Test> = ArrayList()
inner class TestVH(val bin: ItemTestBinding) : RecyclerView.ViewHolder(bin.root) {
fun bind(test: Test) {
bin.tvTestId.text = "[id: ${test.id}]"
bin.tvTestTitle.text = test.title
bin.cbTest.isChecked = test.select
bin.cbTest.setOnClickListener {
click.click(test)
}
}
}
fun sumbitData(newl: ArrayList<Test>) {
val diff = DiffCB(this.list, newl)
val diffResult = DiffUtil.calculateDiff(diff)
list.clear()
this.list.addAll(newl)
diffResult.dispatchUpdatesTo(this)
}
override fun getItemCount(): Int {
return list.size
}
override fun onBindViewHolder(holder: TestVH, position: Int) {
holder.bind(list[position])
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TestVH {
return TestVH(ItemTestBinding.inflate(LayoutInflater.from(parent.context),
parent, false))
}
}
my Activity.kt
class TestActivity : AppCompatActivity(), TestClick {
private var list : ArrayList<Test> = ArrayList()
private lateinit var bin : ActivityTestBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
bin = ActivityTestBinding.inflate(layoutInflater)
setContentView(bin.root)
val viewModel = ViewModelProviders.of(this).get(TestViewModel::class.java)
val manager = LinearLayoutManager(this)
bin.rvTest.layoutManager = manager
val adapter = TestAdapter(this)
bin.rvTest.adapter = adapter
//init first data
viewModel.setTests(initData())
viewModel.getTests().observe(this, Observer {
adapter.sumbitData(it as ArrayList<Test>)
})
bin.btnTest.setOnClickListener{
viewModel.setTests(updateData())
}
}
fun updateData() : ArrayList<Test> {
for (i in 2..6) {
var test = Test()
test.id = i
test.title = "title test $i update"
list.add(test)
}
return list
}
fun initData() : ArrayList<Test> {
for (i in 1..3) {
var test = Test()
test.id = i
test.title = "title test $i"
list.add(test)
}
return list
}
override fun click(test: Test) {
Toast.makeText(this, "${test.id} ${test.title}", Toast.LENGTH_SHORT).show()
}
}
it is first data
after update data, items with the same id have not been updated (id 2, 3)

Data fetch from API not showing on recyclerview MVVM kotlin

I got blocked for this problem, Api will call and get the objects from the response and it will display on the recyclerview. But it is not showing,
fetchProductCategories will do the api call.
prepareProducts will handle the fetched from fetchProductCategories
Fragment:
#AndroidEntryPoint
class ProductsWelcomeFragment : BaseProductsFragment<ProductsWelcomeViewModel, ProductsWelcomeFragmentBinding>() {
private val TAG = "ProductsWelcomeFragment"
#Inject
lateinit var animationQueue: AnimationQueue
override fun getViewModelClass(): KClass<ProductsWelcomeViewModel> = ProductsWelcomeViewModel::class
override fun getContentViewRes(): Int = R.layout.products_welcome_fragment
private val cordovaViewModel: CordovaViewModel by activityViewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
/**
* Initialize only once when everytime accessing products screen.
* */
sharedViewModel.initialSetUpRequest()
viewModel.fetchProductCategories()
}
override fun onBindView() {
with(dataBinding) {
viewModel = this#ProductsWelcomeFragment.viewModel
title = getString(R.string.products_screen_welcome_header)
recyclerViewProducts.configure()
executePendingBindings()
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.productCategoriesLiveData.observe(viewLifecycleOwner) {
Log.i(TAG, it.toString())
viewModel.items.observe(viewLifecycleOwner) {
viewModel.prepareProducts()
}
}
viewModel.showProgress.observe(viewLifecycleOwner) {}
viewModel.failedAtRetrievingData.observe(viewLifecycleOwner) {
// showErrorScreen(true)
}
}
private fun RecyclerView.configure() {
with(dataBinding.recyclerViewProducts) {
addItemBindings(SectionHeaderItemViewBinder)
addItemBindings(SpaceItemViewDtoBinder)
addItemBindings(getListButtonItemViewBinder(ProductItem.NormalProduct::dto, ::onProductItemClick))
addItemBindings(getListBigtileItemViewBinder(ProductItem.FeaturedProduct::dto, ::onProductItemClick))
}
}
private fun onProductItemClick(product: ProductItem.NormalProduct) {
when (product.id) {
else -> { // TODO : )}
}
// TODO : implement move to another screen
}
private fun onProductItemClick(product: ProductItem.FeaturedProduct) {
// TODO : implement move to another screen
}
private fun showErrorScreen(isDataRetrievalError: Boolean) {
val dismissAction = ErrorHandlingAction(
getString(R.string.native_done),
null,
null,
ButtonType.PRIMARY
) { dismissDialog ->
dismissDialog.dismiss()
if (isDataRetrievalError) {
findNavController().popBackStack()
}
}
DialogFactory().showBottomDialog(
fragmentManager = parentFragmentManager,
window = requireActivity().window,
title = getString(R.string.native_error_title),
description = getString(R.string.online_identity_something_went_wrong_error_description),
iconId = R.drawable.ic_error_thick_exclamation_icon,
errorHandlingActions = arrayOf(dismissAction),
isHtmlDescription = true
)
}
private fun openCordovaScreen(destination: CordovaPage) {
cordovaViewModel.requestPage(destination)
findNavController().popBackStack(R.id.homeScreenMainFragment, false)
}
}
ViewModel:
#HiltViewModel
class ProductsWelcomeViewModel #Inject constructor(
private val productsRepository: ProductsRepository
) : BaseRequestViewModel(), ViewModelWithItems {
private val TAG = "ProductsWelcomeViewModel"
private val _failedAtRetrievingData = SingleLiveEvent<Boolean>()
val failedAtRetrievingData: LiveData<Boolean> = _failedAtRetrievingData
private val _showProgress = MutableLiveData<Boolean>()
val showProgress: LiveData<Boolean> = _showProgress
private val onProductCategories: SingleLiveEvent<ProductBasketsCategoriesModel?> = SingleLiveEvent()
val productCategoriesLiveData: LiveData<ProductBasketsCategoriesModel?> = onProductCategories
private val _items: MutableLiveData<List<Any>> = MutableLiveData()
override val items: LiveData<List<Any>> = _items
fun fetchProductCategories() {
viewModelScope.launch {
request({ productsRepository.getProductCategories() },
success = { response -> onProductCategories.value = response },
failure = { })
}
}
fun prepareProducts() {
_items.value = mutableListOf<Any>().apply {
productCategoriesLiveData.value?.embedded?.categories?.filter { categories ->
categories.isFeatured == true }?.let { filteredCategories ->
add(HeaderItem(ListSectionHeaderItemViewDto(
text = TextLine(
textRes = if (filteredCategories.isNotEmpty()) {
R.string.products_screen_welcome_header } else { null }
)
)
))
filteredCategories.toItems()?.let { addAll(it) }
}
productCategoriesLiveData.value?.embedded?.categories?.filter { categories ->
categories.isFeatured == false }.let { filteredCategories ->
if (filteredCategories != null) {
add(HeaderItem(ListSectionHeaderItemViewDto(
text = TextLine(
textRes = if (filteredCategories.isNotEmpty()) {
R.string.products_screen_welcome_header } else { null }
)
)
))
}
filteredCategories.toItems()?.let { addAll(it) }
}
}
}
private fun List<CategoriesItemModel>?.toItems(): List<ProductItem>? =
this?.mapIndexed { index, item ->
if (item.isFeatured == true) {
ProductItem.FeaturedProduct(
id = item.id as Any,
name = item.name,
dto = BigTileDto(
title = TextLine(text = item.name),
image = item.id.toString().let { toFeatureIcon(it, item.isFeatured) },
description = TextLine(item.description.toString()),
background = BackgroundType.SINGLE
)
)
} else {
ProductItem.NormalProduct(
id = item.id as Any,
name = item.name,
dto = ListButtonItemViewDto(
firstLine = TextLine(text = item.name),
rightDrawable = R.drawable.ic_arrow_right,
separatorDrawable = R.drawable.list_divider_margin_start_72dp,
background = index.indexToBackgroundType(this.size),
avatarDto = AvatarDto(iconBackgroundColor = R.color.ubs_concrete, avatarSize = AvatarDto.AvatarSize.SMALL_ICON_SIZE, iconId = toFeatureIcon(
item.id, item.isFeatured
)),
)
)
}
}
private fun toFeatureIcon(id: String?, isFeature: Boolean?): Int = if (ProductFeature.verify(id) == true) {
ProductFeature.icon()
} else { if (isFeature == true) { R.drawable.abc_vector_test } else {
R.drawable.balloon_illustration } }
}

Can't Update child item in NestedRecyclerView

How do I update the child when clicking on the categories item or when doing a search like the one in the picture
I am updating the data from Viewmodel but the child element does not update
I also tried calling the adapter child and updating it directly, but to no avail
This is the code, if you need any additional details, I will add it down
In ParentAdapter
class BaseAdapter(private val listener: OnItemClickListener
): RecyclerView.Adapter<BaseViewHolder>() {
var items : MutableList<HomeItem<Any>> = mutableListOf()
lateinit var adapter : SubjectsAdapter
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder {
return when (viewType){
VIEW_ITEM_SEARCH ->{
val view = LayoutInflater.from(parent.context).inflate(
R.layout.item_search_view,
parent,false
)
BaseViewHolder.SearchItemViewHolder(view)
}
VIEW_ITEM_STUDENT ->{
val view = LayoutInflater.from(parent.context).inflate(
R.layout.item_student, parent,false
)
BaseViewHolder.StudentItemViewHolder(view)
}
VIEW_ITEM_COLOR ->{
val view = LayoutInflater.from(parent.context).inflate(
R.layout.item_chip_list, parent,false
)
BaseViewHolder.YearsItemViewHolder(view)
}
VIEW_ITEM_SUBJECT ->{
val view = LayoutInflater.from(parent.context).inflate(
R.layout.item_subject_list, parent,false
)
BaseViewHolder.SubjectsItemViewHolder(view)
}
else -> throw Exception("UnKnow View Type")
}
}
override fun onBindViewHolder(holder: BaseViewHolder, position: Int) {
when (holder){
is BaseViewHolder.SearchItemViewHolder -> bindSearch(holder,position)
is BaseViewHolder.StudentItemViewHolder -> bindStudent(holder,position)
is BaseViewHolder.YearsItemViewHolder -> bindYears(holder,position)
is BaseViewHolder.SubjectsItemViewHolder -> bindSubjects(holder,position)
}
}
fun bindYears(holder: BaseViewHolder.YearsItemViewHolder,position: Int){
val p = items[position].item as List<SubjectsColor>
val adapterchip = ChipAdapter { chip ->
listener.onSubjectColorClick(chip)
}
holder.binding.apply {
recyclerChipList.layoutManager = LinearLayoutManager(root.context,
LinearLayoutManager.HORIZONTAL,
false)
recyclerChipList.adapter = adapterchip
recyclerChipList.setHasFixedSize(true)
}
adapterchip.submitList(p)
}
fun bindSubjects(holder :BaseViewHolder.SubjectsItemViewHolder,position: Int){
val p = items[position].item as List<SubjectStudent>
adapter = SubjectsAdapter{ subject->
listener.onSubjectStudentClick(subject)
}
holder.binding.apply {
recyclerSubjectList.layoutManager = LinearLayoutManager(root.context,
LinearLayoutManager.VERTICAL,
false)
recyclerSubjectList.adapter = adapter
recyclerSubjectList.setHasFixedSize(true)
}
Log.d("BindSubjects","BindSubjects : $p")
adapter.submitList(p)
}
In ViewModel
#HiltViewModel
class HomeViewModel #Inject constructor(
private val subDao : SubjectsDao,
//state : SavedStateHandle
) : ViewModel(){
private val colorId = MutableLiveData(1)
val colorIdResult = colorId.asFlow().flatMapLatest(){ id ->
id.let {
subDao.getAllSubjectStudentByColor(id)
}
}.stateIn(viewModelScope, SharingStarted.Lazily, null)
fun getAllSubjectsColor() :Flow<List<SubjectsColor>> =
subDao.getAllSubjectColors()
fun onSubjectColorClick(colorI:Int){
colorId.postValue(colorI)
}}
In Fragment
adapterBase = BaseAdapter(this)
val itemsList: MutableList<HomeItem<Any>> = mutableListOf()
itemsList.add(HomeItem("Google Home", HomeItemType.TYPE_SEARCH))
itemsList.add(HomeItem("Student", HomeItemType.TYPE_PROFILE))
viewLifecycleOwner.lifecycleScope.launchWhenStarted {
viewModel.getAllSubjectsColor().collect {
itemsList.add(HomeItem(it, HomeItemType.TYPE_COLORS))
}
}
viewLifecycleOwner.lifecycleScope.launchWhenStarted {
viewModel.colorIdResult.collect { id ->
val result = id ?: return#collect
itemsList.add(HomeItem(result.subjectStudent, HomeItemType.TYPE_SUBJECTS))
//adapterBase.notifyDataSetChanged()
}
}
binding.apply {
recyclerBaseFragment.layoutManager = LinearLayoutManager(requireContext())
recyclerBaseFragment.setHasFixedSize(true)
recyclerBaseFragment.adapter = adapterBase
}
adapterBase.items = itemsList
}
enum class HomeItemType {
TYPE_SEARCH,
TYPE_PROFILE,
TYPE_COLORS,
TYPE_SUBJECTS
}
data class HomeItem<T>(
var item :T,
val type: HomeItemType
)

Recyclerview keep being reset

I'm facing a problem with my recycler view, I'd wanted to refresh it every second, for that I use a timer which creates new request, but I think that my recyclerview is destroyed and directly recreated, when I'm scrolling it keep always returning to the top every second. Here is my fragment, I heard about layoutmanager but don't really know how to use it, is it linked?
class DlFragment (private val context: MainActivity): Fragment(){
private var myTimer: Timer? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_dl,container, false)
val dlRecyclerView = view?.findViewById<RecyclerView>(R.id.dl_list_recycle_view)
myTimer = Timer()
myTimer!!.schedule(object : TimerTask() {
override fun run() {
getDlList(dlRecyclerView)
}
}, 0, 1000)
val comfirmButton= view.findViewById<Button>(R.id.input_post_dl_button)
comfirmButton.setOnClickListener { postDl(view) }
return view
}
private fun getDlList(dlRecyclerView: RecyclerView?) {
GlobalScope.launch(Dispatchers.Main) {
try {
val response = ApiClientQnap.apiServiceQnap.getQuery(0,20,"all","all",ApiClientQnap.sid)
if (response.isSuccessful && response.body() != null) {
val content = response.body()
if (content != null) {
//println(content)
//val dlRecyclerView = view?.findViewById<RecyclerView>(R.id.dl_list_recycle_view)
dlRecyclerView?.adapter = DlAdapter(context,content.data)
}
} else { println("Error Occurred: ${response.message()}") }
} catch (e: Exception) {println("Error Occurred: ${e.message}") }
}
}
private fun postDl(view: View){
val url_Dl = view.findViewById<EditText>(R.id.input_post_dl_text)
GlobalScope.launch(Dispatchers.Main) {
try {
val response = ApiClientQnap.apiServiceQnap.postDL("Films","Films",
url_Dl.text.toString(),ApiClientQnap.sid)
if (response.isSuccessful && response.body() != null) {
val content = response.body()
println(response.body())
if (content != null) {
if(content.error == 0) {
Toast.makeText(context, "yeee", Toast.LENGTH_LONG).show()
url_Dl.text.clear()
}
else
Toast.makeText(context, "no", Toast.LENGTH_LONG).show()
}
} else { println("Error Occurred: ${response.message()}") }
} catch (e: Exception) {println("Error Occurred: ${e.message}") }
}
}
Edit: Here's my DlAdapter
class DlAdapter(
val context: MainActivity,
private var dlList: ArrayList<Data>
) : RecyclerView.Adapter<DlAdapter.ViewHolder>() {
class ViewHolder(view : View): RecyclerView.ViewHolder(view){
val dl_title = view.findViewById<TextView>(R.id.dl_title)
val dl_progress = view.findViewById<TextView>(R.id.dl_progress)
val dl_speed = view.findViewById<TextView>(R.id.dl_speed)
val progressBar = view.findViewById<ProgressBar>(R.id.progressBar)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater
.from(parent.context)
.inflate(R.layout.fragment_dl_list,parent,false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val currentDl = dlList[position]
holder.dl_title.text = currentDl.source_name
holder.progressBar.progress = (currentDl.progress!!)
when (currentDl.state) {
5 -> holder.dl_progress.text = ("Terminé")
2 -> holder.dl_progress.text = ("Arrété")
4 -> holder.dl_progress.text = ("Echec")
1 -> holder.dl_progress.text = (currentDl.progress.toString() + " % En pause")
104 -> {
holder.dl_progress.text = (currentDl.progress.toString() + " %")
var toFloat = currentDl.down_rate?.toFloat()
toFloat = toFloat?.div(1000000)
holder.dl_speed.text = (toFloat.toString()+" Mo")
}
}
}
override fun getItemCount(): Int = dlList.size
fun updateData(newData: ArrayList<Data>) {
dlList.clear()
dlList.addAll(newData)
notifyDataSetChanged()
}
}
As #hardartcore suggested, you can try to convert the RecyclerView.Adapter to a ListAdapter and use a DiffUtil.ItemCallback class.
Try to convert your adapter like this:
class DlAdapter : ListAdapter<Data, DlAdapter.ViewHolder>(DlDiffCallback()) {
class ViewHolder(view : View): RecyclerView.ViewHolder(view){
val dl_title = view.findViewById<TextView>(R.id.dl_title)
val dl_progress = view.findViewById<TextView>(R.id.dl_progress)
val dl_speed = view.findViewById<TextView>(R.id.dl_speed)
val progressBar = view.findViewById<ProgressBar>(R.id.progressBar)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater
.from(parent.context)
.inflate(R.layout.fragment_dl_list,parent,false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
// Use the getItem method to retrieve a specific item
val currentDl = getItem(position)
holder.dl_title.text = currentDl.source_name
holder.progressBar.progress = (currentDl.progress!!)
when (currentDl.state) {
5 -> holder.dl_progress.text = ("Terminé")
2 -> holder.dl_progress.text = ("Arrété")
4 -> holder.dl_progress.text = ("Echec")
1 -> holder.dl_progress.text = (currentDl.progress.toString() + " % En pause")
104 -> {
holder.dl_progress.text = (currentDl.progress.toString() + " %")
var toFloat = currentDl.down_rate?.toFloat()
toFloat = toFloat?.div(1000000)
holder.dl_speed.text = (toFloat.toString()+" Mo")
}
}
}
}
class DlDiffCallback : DiffUtil.ItemCallback<Data>() {
// Change this method comparisons based on your equality conditions
override fun areItemsTheSame(oldItem: DataItem, newItem: DataItem): Boolean = oldItem.id == newItem.id
override fun areContentsTheSame(oldItem: DataItem, newItem: DataItem): Boolean = oldItem == newItem
}
You can then update your RecyclerView adapter by using the submitList method:
val adapter = DlAdapter()
adapter.submitList(content.data)

Unresolved reference: myViewHolder after switching to View Binding

After switching from removing kotlin_extensions and switching to view binding, I received a "Unresolved reference: myViewHolder" in my onBindViewHolder method and when I replace "myViewHolder" with "holder", it then gives me a "Unresolved reference: bind". How do I resolve this.
MyAdapter
class MyAdapter(private val context: Context, private val mHelper : TaskDbHelper) : RecyclerView.Adapter<MyAdapter.MyViewHolder>(),
SwipeAndDragHelper.ActionCompletionContract {
class MyViewHolder(val binding: CellCardsBinding): RecyclerView.ViewHolder(binding.root ) {
fun binding() {
}
}
private var touchHelper: ItemTouchHelper? = null
private var list = mutableListOf<MyObject>()
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
initList()
super.onAttachedToRecyclerView(recyclerView)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
return MyViewHolder(CellCardsBinding.inflate(LayoutInflater.from(parent.context), parent, false))
}
#RequiresApi(Build.VERSION_CODES.P)
#SuppressLint("ClickableViewAccessibility")
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val myObject = list[position]
myViewHolder.bind(myObject)
val activity: Activity = context as Activity
holder.binding.text.setOnClickListener{
activity.launchActivity<AddNoteActivity>(42) {
putExtra("PositionInList", position.toString())
putExtra("TaskTitle", myObject.title)
putExtra("TaskText", myObject.text)
}
}
activity.findViewById<RecyclerView>(R.id.recyclerView).setOnTouchListener { _, event ->
when (event.actionMasked) {
MotionEvent.ACTION_UP -> {
updateNotesPositionInDb()
false
}
else -> {
false
}
}
}
holder.binding.title.setOnTouchListener { _, event ->
when (event.actionMasked) {
MotionEvent.ACTION_DOWN -> {
touchHelper!!.startDrag(holder)
false
}
else -> {
false
}
}
}
}
private fun initList() {
list.clear()
val db = mHelper.readableDatabase
val cursor = db.query(
TaskContract.TaskEntry.TABLE,
arrayOf(
TaskContract.TaskEntry.ID,
TaskContract.TaskEntry.COL_TASK_TITLE,
TaskContract.TaskEntry.COL_TASK_TEXT,
TaskContract.TaskEntry.COL_TASK_DATE),null, null, null, null, TaskContract.TaskEntry.ID)
while (cursor.moveToNext()) {
val id = cursor.getColumnIndex(TaskContract.TaskEntry.ID)
val idTitle = cursor.getColumnIndex(TaskContract.TaskEntry.COL_TASK_TITLE)
val idText = cursor.getColumnIndex(TaskContract.TaskEntry.COL_TASK_TEXT)
val idDate = cursor.getColumnIndex(TaskContract.TaskEntry.COL_TASK_DATE)
list.add(MyObject(cursor.getString(id), cursor.getString(idTitle), cursor.getString(idText), cursor.getString(idDate)))
}
notifyDataSetChanged()
cursor.close()
db.close()
}
override fun getItemCount(): Int {
return list.size
}
override fun onViewMoved(oldPosition: Int, newPosition: Int) {
val target = list[oldPosition]
list.removeAt(oldPosition)
list.add(newPosition, target)
notifyItemMoved(oldPosition, newPosition)
}
override fun onViewSwiped(position: Int) {
deleteTask(list[position].ID)
list.removeAt(position)
notifyItemRemoved(position)
updateNotesPositionInDb()
}
fun setTouchHelper(touchHelper: ItemTouchHelper) {
this.touchHelper = touchHelper
}
fun addTask(taskTitle : String, taskText: String) {
val values = ContentValues()
val sdf = SimpleDateFormat("dd/MM/yyyy/", Locale.US)
val date = sdf.format(Date())
values.put(TaskContract.TaskEntry.ID, list.size)
values.put(TaskContract.TaskEntry.COL_TASK_TITLE, taskTitle)
values.put(TaskContract.TaskEntry.COL_TASK_TEXT, taskText)
values.put(TaskContract.TaskEntry.COL_TASK_DATE, date)
val db = mHelper.readableDatabase
db.insertWithOnConflict(TaskContract.TaskEntry.TABLE,
null,
values,
SQLiteDatabase.CONFLICT_REPLACE)
db.close()
list.add(MyObject(list.size.toString(), taskTitle, taskText, date))
notifyItemInserted(list.size)
}
fun addTask() {
val test: Activity = context as Activity
test.launchActivity<AddNoteActivity>(42) {
/* putExtra("user", "854")
p utExtra("user2", "46850") */
}
}
private fun deleteTask(taskId: String) {
val db = mHelper.readableDatabase
db.delete(TaskContract.TaskEntry.TABLE,
"id=$taskId", null)
db.close()
}
fun modifyTask(taskPosition: String, taskTitle: String, taskText: String) {
val target = list[taskPosition.toInt()]
target.title = taskTitle
target.text = taskText
val values = ContentValues()
val sdf = SimpleDateFormat("dd/MM/yyyy/", Locale.US)
val date = sdf.format(Date())
values.put(TaskContract.TaskEntry.ID, taskPosition)
values.put(TaskContract.TaskEntry.COL_TASK_TITLE, taskTitle)
values.put(TaskContract.TaskEntry.COL_TASK_TEXT, taskText)
values.put(TaskContract.TaskEntry.COL_TASK_DATE, date)
val db = mHelper.readableDatabase
db.update(TaskContract.TaskEntry.TABLE,
values, TaskContract.TaskEntry.ID + "=" + target.ID, null)
db.close()
notifyItemChanged(taskPosition.toInt())
}
private fun updateNotesPositionInDb() {
val db = mHelper.readableDatabase
var i = 0
while (i < list.size) {
val values = ContentValues()
values.put(TaskContract.TaskEntry.ID, i)
db.update(TaskContract.TaskEntry.TABLE,
values, TaskContract.TaskEntry.ID + "=? AND " + TaskContract.TaskEntry.COL_TASK_TITLE + "=?", arrayOf(list[i].ID, list[i].title))
i++
}
db.close()
}
I've tried reading Android Studio's official documentation, but it cannot solve my specific problem.
in your class MyViewHolder you have method called binding and you need also to implement it and add paramter
shoud be
class MyViewHolder(private val binding: CellCardsBinding): RecyclerView.ViewHolder(binding.root ) {
fun bind(data:MyObject) {
binding.yourView=data.title ...
}
}
in onBindViewHolder
..
holder.bind(myObject)
After switching from removing kotlin_extensions and switching to view binding, I received a "Unresolved reference: myViewHolder" in my onBindViewHolder method
Well, your onBindViewHolder method is passing a variable called holder and you're trying to use a variable called myViewHolder, so that seems like a problem.
// --------------------this-----v
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val myObject = list[position]
// v--- doesn't match this
myViewHolder.bind(myObject)
and when I replace "myViewHolder" with "holder", it then gives me a "Unresolved reference: bind". How do I resolve this.
Your MyViewHolder class has a method called binding that takes no arguments. There is no bind method that takes a "myObject".
class MyViewHolder(val binding: CellCardsBinding): RecyclerView.ViewHolder(binding.root ) {
fun binding() {
}
}
Edit
You should pass an instance of the data class
class MyViewHolder(val binding: CellCardsBinding): RecyclerView.ViewHolder(binding.root ) {
fun bind(object: MyObject) {
// Set variables on binding
}
}
Then pass an instance from your list via onBindViewHolder:
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val myObject = list[position]
holder.bind(myObject)
Please check this blog post for more.
I got my answer.
class MyAdapter(private val context: Context, private val mHelper : TaskDbHelper) : RecyclerView.Adapter<MyAdapter.MyViewHolder>(),
SwipeAndDragHelper.ActionCompletionContract {
class MyViewHolder(val binding: CellCardsBinding): RecyclerView.ViewHolder(binding.root ) {
private val titleView: TextView = itemView.findViewById<View>(R.id.title) as TextView
val textView: TextView = itemView.findViewById<View>(R.id.text) as TextView
private val dateTextView: TextView = itemView.findViewById<View>(R.id.date) as TextView
fun binding (myObject: MyObject) {
titleView.text = myObject.title
textView.text = myObject.text
dateTextView.text = myObject.date
}
}
I simply initialised the view I wanted to reference in my layout and called them in the binding() function.