• 4
name

A PHP Error was encountered

Severity: Notice

Message: Undefined index: userid

Filename: views/question.php

Line Number: 191

Backtrace:

File: /home/prodcxja/public_html/questions/application/views/question.php
Line: 191
Function: _error_handler

File: /home/prodcxja/public_html/questions/application/controllers/Questions.php
Line: 433
Function: view

File: /home/prodcxja/public_html/questions/index.php
Line: 315
Function: require_once

I have a chat in my application and I want my RV stay on position 0 when the new message comes and the first visible item position is 0, but new messages are added above the currently visible one, but the visible items stay in view so user has to scroll to see new message.

My adapter was extended from RecyclerView.Adapter<RecyclerView.ViewHolder> and I found a little hacky solution to get it work:

private suspend fun update(newItems: List<IChatItem>) {
    var recyclerViewState: Parcelable? = null
    if ((recyclerView?.layoutManager as LinearLayoutManager).findFirstCompletelyVisibleItemPosition() == 0) {
        recyclerViewState = recyclerView?.layoutManager?.onSaveInstanceState()
    }

    val diffResult = withContext(Dispatchers.Default) {
        DiffUtil.calculateDiff(Diff(this.currentItems, newItems))
    }

    diffResult.dispatchUpdatesTo(this)

    recyclerViewState?.let {
        recyclerView?.layoutManager?.onRestoreInstanceState(recyclerViewState)
    }
}

The thing is saving RV state and after DiffUtil completes it's work, restore it. It did work, but now I'm trying to implement new adapter and extend my adapter class from ListAdapter because it launches DiffUtil in another thread. It works good, but the problem is I can't implement my previous solution here, it just doesn't work.

I tried following:

override fun submitList(list: MutableList<IChatItem>?) {
    var recyclerViewState: Parcelable? = null
    if ((recyclerView?.layoutManager as LinearLayoutManager).findFirstCompletelyVisibleItemPosition() == 0) {
        recyclerViewState = recyclerView?.layoutManager?.onSaveInstanceState()
    }

    super.submitList(list)

    recyclerViewState?.let {
        recyclerView?.layoutManager?.onRestoreInstanceState(recyclerViewState)
    }
}

But this doesn't work anymore. Does anybody have a solution?

PS: I found this question - Inserting RecyclerView items at zero position - always stay scrolled to top, but I don't think this is the best solution to add empty invisible items in adapter's list. Any other ideas?

UPD: as I thought - because this adapter launches DiffUtil in another thread, it restored RV state before DiffUtil completes it's job. This code works:

override fun submitList(list: List<IChatItem>?) {
    var recyclerViewState: Parcelable? = null
    if ((recyclerView?.layoutManager as LinearLayoutManager).findFirstCompletelyVisibleItemPosition() == 0) {
        recyclerViewState = recyclerView?.layoutManager?.onSaveInstanceState()
    }


    super.submitList(list)

    recyclerViewState?.let {
            Handler().postDelayed( 
                { 
                    recyclerView?.layoutManager?.onRestoreInstanceState(recyclerViewState) 
                }, 1000
            )
    }
}

But ofc this is not what I want. Is there any way to detect when DiffUtil is done with everything?

    • @B.Plüster well, maybe I should say that I have a reverse layout and new messages should be added on bottom of the screen.. And if I do "stackFromEnd" my RV just scrolls to top (to oldest messages)