0

I have a recyclerView. When I do the pull to refresh, if the new data is just one list item, then the recycler view loads the item perfectly. But if the updated data contains 2 or more, then I think the view is not recycled properly. In the actionContainer, there should only one item to be added for each of the updated list item. But during pull to refresh, ONLY WHEN there are 2 or more list items to be updated, the actionContainer shows 2 data where it should be only one. Can someone help me to fix this?

override fun onBindViewHolder(holder: HistoryListAdapter.ViewHolder?, position: Int) {
            info("onBindViewHolder =>"+listAssets.size)
            info("onBindViewHolder itemCount =>"+itemCount)
            info("onBindViewHolder position =>"+position)
        val notesButton = holder?.notesButton
        val notesView = holder?.notesTextView

        val dateTime = listAssets[position].date
        val location = listAssets[position].location

        val sessionId = listAssets[position].id
        holder?.sessionID = sessionId
        holder?.portraitImageView?.setImageDrawable(listAssets[position].image)
        holder?.titleTextView?.text = DateTimeFormatter.getFormattedDate(context, dateTime)

        val timeString = DateTimeFormatter.getFormattedTime(context, dateTime)

        if (location.length != 0) {
            holder?.subtitleTextView?.text = "$timeString @ $location"
        } else {
            holder?.subtitleTextView?.text = "$timeString"
        }

        val data = listAssets[position].data

        for (actionData in data) {
            val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
            val parent = inflater.inflate(R.layout.history_card_action, null)

            val icon = parent?.findViewById(R.id.historyActionIcon) as ImageView
            val title = parent?.findViewById(R.id.historyActionTitle) as TextView
            val subtitle = parent?.findViewById(R.id.historyActionSubtitle) as TextView

            var iconDrawable: Drawable? = null

            when(actionData.type) {

                ActionType.HEART -> {
                    iconDrawable = ContextCompat.getDrawable(context, R.drawable.heart)
                }
                ActionType.LUNGS -> {
                    iconDrawable = ContextCompat.getDrawable(context, R.drawable.lungs)
                }
                ActionType.TEMPERATURE -> {
                    iconDrawable = ContextCompat.getDrawable(context, R.drawable.temperature)
                }
            }

            icon.setImageDrawable(iconDrawable)

            val titleString = actionData.title

            titleString?.let {
                title.text = titleString
            }

            val subtitleString = actionData.subtitle

            subtitleString?.let {
                subtitle.text = subtitleString
            }

            holder?.actionContainer?.addView(parent)
        }


        val notes = listAssets[position].notes
        notesView?.text = notes

        if (notes.length == 0) {
            notesButton?.layoutParams?.width = 0
        } else {
            notesButton?.layoutParams?.width = toggleButtonWidth
        }

        if (expandedNotes.contains(sessionId)) {
            notesView?.expandWithoutAnimation()
        } else {
            notesView?.collapseWithoutAnimation()
        }

        notesButton?.onClick {
            notesView?.toggleExpansion()
        }
    }


        data class ListAssets(val id: String,
                                  val date: Date,
                                  val location: String,
                                  val notes: String,
                                  val image: Drawable,
                                  val data: ArrayList<ListData>)

            data class ListData(val type: ActionType,
                                val title: String?,
                                val subtitle: String?)

    override fun onViewRecycled(holder: HistoryListAdapter.ViewHolder?) {
            super.onViewRecycled(holder)

            if (holder != null) {
    holder.actionContainer.removeAllViewsInLayout()
                holder.actionContainer.removeAllViews()

                val notesTextView = holder.notesTextView

                if (notesTextView != null) {
                    if (notesTextView.expandedState) {
                        val sessionID = holder.sessionID

                        sessionID?.let {
                            val sessionSearch = expandedNotes.firstOrNull {
                                it.contentEquals(sessionID)
                            }

                            if (sessionSearch == null) {
                                expandedNotes.add(sessionID)
                            }
                        }

                    } else {
                        val sessionID = holder.sessionID

                        sessionID?.let {
                            val sessionSearch = expandedNotes.firstOrNull {
                                it.contentEquals(sessionID)
                            }

                            if (sessionSearch != null) {
                                expandedNotes.remove(sessionSearch)
                            }
                        }
                    }
                }
            }

        }
User
  • 1,186
  • 4
  • 22
  • 36

3 Answers3

0

First, you should probably not override onViewRecycled() unless you have to perform some very particular resources cleanup. The place where you want to setup your views before display is onBindViewHolder().

Second, you don't need not add or remove views dynamically in a RecyclerView item, it's simpler and more efficient to only switch the visibility of the view between VISIBLE and GONE. In cases where this is not enough because views are too different, you should declare different view types, which will create separate ViewHolders for each view type.

BladeCoder
  • 12,779
  • 3
  • 59
  • 51
0

You should not remove or add any view while overriding onBindViewHoder() method of RecyclerView Adapter because next time when a recycled layout is used, the removed views will not be found. Instead of this you can use show/hide on a view.

If you add any view to the layout dynamically, later on when this layout is recycled, it also contains the extra view which you have added before.

Similarly, if you remove any view from the layout dynamically, later on when this layout is recycled, it does not contain the view which you have removed earlier.

Flexo
  • 87,323
  • 22
  • 191
  • 272
Sachin Saxena
  • 604
  • 5
  • 10
0

I have implemented a RecyclerView and Retrofit,it has the SwipeView layout (Pull to Refresh).Here is the link to the repisitory. https://github.com/frankodoom/Retrofit-RecyclerVew

Frank Odoom
  • 1,545
  • 18
  • 19