简体   繁体   中英

RecyclerView onCreateViewHolder not called after notifyItemRangeInserted

Here is my recyclerView init:

messageList = findViewById(R.id.fragmentMessenger_list)
val layoutManager = LinearLayoutManager(activity)
layoutManager.stackFromEnd = true
messageList.layoutManager = layoutManager
messageList.adapter = messengerAdapter

all works fine here.

when I receive new data list, I am trying to update recyclerViewAdapter with help of diffUtil:

fun swap(list: ArrayList<QMessage>){       
    val diffUtilCallback = ListDiffUtilCallback(itemsList, list)
    val diffResult = DiffUtil.calculateDiff(diffUtilCallback)

    itemsList.clear()
    itemsList.addAll(list)
    diffResult.dispatchUpdatesTo(this@MessengerAdapter)
}

I know that it recomended to use in separate thread, but just for example diffUtill work in ui thread

So each time when there are some data updates, I receive a new list of all messages.

The problem is that when I already have few messages (for example two), and they are bigger than one screen (we need to swipe to see them full) and receive 3rd one - adapter doesn't scroll to bottom. but if even I do it manually, there is no 3rd message! Until I make some swipe up and then down again!

Is anybody familiar with this kind of?

Any ideas why it's happening and how to fix?

UPDATE: by the way, the same behavior with next swapping data:

val position = itemsList.size +1
itemsList.addAll(newItems)
notifyItemRangeInserted(position, newItems.size)

UPDATE 2: just figured with the logs that after insert getItemCount return correct list size (so this method was called), but onCreateViewHolder was not called after insert!

UPDATE 3: here is my adapter: class MyAdapter(): RecyclerView.Adapter() {

    interface MessageClickListener{
    }

    private var listener:MessageClickListener? = null
    private lateinit var layoutManager: LinearLayoutManager
    private var itemsList = ArrayList<QMessage>()
    private var itemsListSize = 0

    override fun getItemCount(): Int {
        itemsListSize = itemsList.size
        L.log("getItemCount $itemsListSize")
        return itemsListSize
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder?, position: Int) {
        L.log("onBindViewHolder position = $position")
        val message = itemsList[position]
        if (holder is MessageType1) {
            L.log("onBindViewHolder MessageType1")
            holder.bind(message, listener)
        } else if (holder is MessageType2) {
            L.log("onBindViewHolder MessageType2")
            holder.bind(message, listener)
        } else if (holder is MessageType3) {
            L.log("onBindViewHolder MessageType3")
            holder.bind(message, listener)
        } else {
            L.log("onBindViewHolder unknown")
        }
    }

    override fun getItemViewType(position: Int): Int {
        val item = itemsList[position]
        return item.type.toInt()
    }

    override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): RecyclerView.ViewHolder? {
        return when(viewType){
            QMessageType.MESSAGE_TYPE_1.toInt() -> {
                L.log("onCreateViewHolder MESSAGE_TYPE_1")
                MessageType1(parent!!)
            }
            QMessageType.MESSAGE_TYPE_2.toInt() -> {
                L.log("onCreateViewHolder MESSAGE_TYPE_2")
                MessageType2(parent!!)
            }
            QMessageType.MESSAGE_TYPE_3.toInt() -> {
                L.log("onCreateViewHolder MESSAGE_TYPE_3")
                MessageType3(parent!!)
            }
            else -> {
                L.log("onCreateViewHolder default")
                return MessageType1(parent!!)
            }
        }
    }

    fun setup(l:MessageClickListener, lm: LinearLayoutManager){
        if (listener != null)
            return
        listener = l
        this.layoutManager = lm
    }


    fun swap(list: ArrayList<QMessage>){
        L.log("swap called. listSize = ${list.size}")
        if (list.isEmpty())
            return

        val newItems = list.minus(itemsList)
        L.log("newItems = ${newItems.size}")

        val position = itemsList.size +1
        itemsList.addAll(newItems)
        notifyItemRangeInserted(position, newItems.size)
    }

}

UPDATE 4: logs:

D: getItemCount 0
D: getItemCount 0
D: swap called. listSize = 0
D: swap called. listSize = 2
D: newItems = 2
D: getItemCount 2
D: getItemCount 2
D: onCreateViewHolder MESSAGE_TYPE_2
D: onBindViewHolder position = 1
D: onBindViewHolder MessageType2
D: getItemCount 2
D: onCreateViewHolder MESSAGE_TYPE_1
D: onBindViewHolder position = 0
D: onBindViewHolder MessageType1
D: getItemCount 2
D: getItemCount 2
D: swap called. listSize = 3
D: newItems = 1
D: getItemCount 3
D: getItemCount 3

as we can see, after second swap there was no onCreateViewHolder call

Just return itemsList.size is enough

override fun getItemCount(): Int {
    L.log("getItemCount $itemsListSize")
    return itemsList.size
}

Put this function outside from your adapter, and replace the new arraylist

fun swap(list: ArrayList<QMessage>){
    itemsList = list
    adapter.notifydatasetchanged()
}

Make sure this variable is outside from your adapter class

private var itemsList = ArrayList<QMessage>()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM