Pis7ftw
Pis7ftw

Reputation: 105

RecyclerView - 2 views updating when I only want 1 to update

I have created a RecyclerView in which the user can press a "Now" button and it would update recycler view's TextViews with the current date and time.

Weirdly, if I press the "Now" button on the recycler view at position 0, it also updates the RecyclerView at position 9. Similarly, pressing it at position 1 also updates it at position 10.

Currently, the date and time are not saved anywhere; that part hasn't been set up yet. I'm just trying to figure out why clicking the button updates two views 10 positions apart.

Here is the code for my adapter; I'm using Kotlin:

class TimeStampListAdapter(private val labelList: ArrayList<TimeStampLabels>,
                       private val context: Context) : RecyclerView.Adapter<TimeStampListAdapter.ViewHolder>() {

override fun onCreateViewHolder(parent: ViewGroup, position: Int): ViewHolder {
    val view: View = LayoutInflater.from(context).inflate(R.layout.list_time_category, parent, false)
    return ViewHolder(view, context, labelList)
}

override fun getItemCount(): Int {
    return labelList.size
}

override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
    viewHolder?.bindItem(labelList[position])

}

 inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), View.OnClickListener {

    var tsDate = itemView.findViewById(R.id.txtEDate) as EditText
    var tsTime = itemView.findViewById(R.id.txtETime) as EditText

    var categoryLabel = itemView.findViewById(R.id.txtVCategory) as TextView

    var nowButton = itemView.findViewById(R.id.btnNow) as Button

    val calendar = Calendar.getInstance()

    // Inserts the time stamp labels into each RecyclerView instance
    fun bindItem(label: TimeStampLabels) {

        categoryLabel.text = label.tsLabel
        nowButton.setOnClickListener(this)

    }



     override fun onClick(v: View?) {
         var dateFormat = SimpleDateFormat("MM / dd / yyyy")
         var timeFormat = SimpleDateFormat("HH:mm")
         var date = dateFormat.format(calendar.timeInMillis)
         var time = timeFormat.format(calendar.getTime())

         // Get the position of relevant row
         var position: Int = adapterPosition
         Log.d("POSITION:  ", position.toString())
         var mList = labelList[position]
         if (v!!.id == nowButton.id) {
             Log.d("POSITION in conditional", position.toString())
             tsDate.setText(date)
             tsTime.setText(time)


             //notifyItemChanged(adapterPosition) - This isn't needed, 
             // but if uncommented doesn't help the main issue I'm    
             // having.
         }

     }

The issue occurs on the firing of the overridden onClick function.

The Activity:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_time_stamp)



    labelListItems = ArrayList()
    adapter = TimeStampListAdapter(labelListItems!!, this )
    layoutManager = LinearLayoutManager(this)


    timeStampRecyclerView.layoutManager = layoutManager
    timeStampRecyclerView.adapter = adapter

    /**
     * Create the recycler views out of the TimeStampLabels table
     */
    for (i in 0..labels.timeStampLabels!!.size - 1) {
        val label = TimeStampLabels()
        label.tsLabel = label.timeStampLabels[i]
        labelListItems!!.add(label)
    }
    adapter!!.notifyDataSetChanged()
}

Upvotes: 2

Views: 139

Answers (1)

SSB
SSB

Reputation: 1034

That is happening because recycler view as name suggests it recycle(reuses) the view so it can save memory and give user smooth scrolling experience, refer this link for more details https://developer.android.com/guide/topics/ui/layout/recyclerview

So you have create two more fields in your model class TimeStampLabels which will store date and time and then you have to change onClick implementation as below

override fun onClick(v: View?) {
    var dateFormat = SimpleDateFormat("MM / dd / yyyy")
    var timeFormat = SimpleDateFormat("HH:mm")
    var date = dateFormat.format(calendar.timeInMillis)
    var time = timeFormat.format(calendar.getTime())

    // Get the position of relevant row
    var position: Int = adapterPosition
    Log.d("POSITION:  ", position.toString())
    var mList = labelList[position]
    // What ever name you give for date and time field in your model class
    mList.date = date
    mList.time = time
    labelList[position] = mList
    notifyDataSetChanged()
}

and change your bindItem method like below

fun bindItem(label: TimeStampLabels) {
    // What ever name you give for date and time field in your model class
    tsDate.setText(label.date)
    tsTime.setText(label.time)
    categoryLabel.text = label.tsLabel
    nowButton.setOnClickListener(this)

}

Upvotes: 1

Related Questions