Auto-moving(at bottom) scrolling on Recylerview not working(Once message loaded) after Updated Paging 3 library

Hello,

I’m currently facing an issue after updated Paging library into message listing screen where once messages(chat) data is loaded but on that Auto-moving scroll at bottom not working in recylerview

I have used same code which exist in sample for pagedlist as below

amityChatSDKMessageListAdapter?.registerAdapterDataObserver(object :
            RecyclerView.AdapterDataObserver() {
            override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
                super.onItemRangeInserted(positionStart, itemCount)
                val lastPosition = amityChatSDKMessageListAdapter!!.itemCount - 1
                //In Paging 3 this condition is never triggered
                if (positionStart == lastPosition) {
                    binding.recyclerviewListMessages.smoothScrollToPosition(lastPosition)
                }
                
                //if i will put this line here it works but Recylerview is jumping
                binding.recyclerviewListMessages.smoothScrollToPosition(lastPosition)
            }
        })

I appreciate any help or suggestion for this issue

Thanks

Hello @vmansuri the team will look into this and we might have further questions. We will keep you posted :pray::blush: Thank you.

Hello @vmansuri

We would like to ask further questions on the issue.
Since “onItemRangeInserted” is still being triggered, but the condition is never met.
What are the values of positionStart and lastPosition, you can currently observe from the log?

Hello,

Thanks for quick reply

As when app open and message data loaded at time following data can be observed before any scroll

2339-2339 E/AmityChatSDK: onItemRangeInserted positionStart 0  itemCount 0 lastPosition -1
2339-2339 E/AmityChatSDK: onItemRangeInserted positionStart 0  itemCount 45 lastPosition 44
2339-2339 E/AmityChatSDK: onItemRangeInserted positionStart 0  itemCount 15 lastPosition 44
2339-2339 E/AmityChatSDK: onItemRangeInserted positionStart 45  itemCount 15 lastPosition 59

Please let me know if anything required

Thanks

Hi @vmansuri ,

Thank you for the log.

Please let me reconfirm the issue you are facing is ,
when entering a message list screen, the recyclerview doesn’t scroll to the current latest message of that channel.

Is this statement correct?

If so, I can confirm that the following condition

 if (positionStart == lastPosition) {
       binding.recyclerviewListMessages.smoothScrollToPosition(lastPosition)
 }

is only for the purpose of scrolling to the newly created message.

So, if the recyclerview doesn’t display the latest message when first entering the message list screen, the problem may lie elsewhere.

We could check

  1. The parameters given to the SDK API for message query
  2. LayoutManager properties such as “stackFromEnd” and “reverseLayout”
  3. Properties of recyclerview in XML file
  4. ViewHolder UI logic (Could be tricky if heights are dynamic).

Yes issue is that when first time chat screen is open after that recylerview should be touch at bottom with smoothly.

  1. The parameters given to the SDK API for message query
@OptIn(ExperimentalPagingApi::class)
    override fun getMessagePagingDataObserver(channelId: String): Flowable<PagingData<AmityMessage>> {
        return messageRepository.getMessages(channelId)
            .stackFromEnd(stackFromEnd = true)
            .parentId(null)
            .build().getPagingData()
    }
  1. LayoutManager properties such as “stackFromEnd” and “reverseLayout”
private fun initialMessageCollection() {
        val layoutManager = LinearLayoutManager(requireContext())
        layoutManager.stackFromEnd = true
        layoutManager.reverseLayout = false
        binding.recyclerviewListMessages.layoutManager = layoutManager
        amityChatSDKMessageListAdapter = AmityChatSDKMessagePagedDataAdapter()

        binding.recyclerviewListMessages.adapter = amityChatSDKMessageListAdapter
        binding.recyclerviewListMessages.addOnScrollListener(AmityPagingDataRefresher(true))

        amityChatSDKMessageListAdapter?.registerAdapterDataObserver(object :
            RecyclerView.AdapterDataObserver() {
            override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
                val lastPosition = amityChatSDKMessageListAdapter!!.itemCount - 1
                super.onItemRangeInserted(positionStart, itemCount)
                AmityChatSDKUtils.printLog("onItemRangeInserted positionStart $positionStart  itemCount $itemCount lastPosition $lastPosition")
                if (positionStart == lastPosition) {
                    binding.recyclerviewListMessages.smoothScrollToPosition(lastPosition)
                }

            }
        })
    }
  1. Properties of recyclerview in XML file
 <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recyclerviewListMessages"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@android:color/white"
            android:paddingTop="8dp"
            android:paddingBottom="8dp"
            tools:listitem="@layout/item_amity_chat_received"
            app:layout_constrainedHeight="true"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintBottom_toTopOf="@+id/view"
            app:layout_constraintTop_toBottomOf="@+id/viewTop" />
  1. ViewHolder UI logic (Could be tricky if heights are dynamic).

<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginStart="8dp"
    android:id="@+id/clMain"
    android:layout_marginTop="16dp">

    <TextView
        android:id="@+id/textViewDateStripe"
        style="@style/AmityChat.DateStripe"
        android:visibility="gone"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:text="June 10" />

    <TextView
        android:id="@+id/textViewMeetingRequestedTitle"
        style="@style/AmityChat.MeetingRequestedTitle"
        android:visibility="gone"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:text="June 10" />

    <androidx.constraintlayout.widget.Guideline
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/guidelineForReceivedChat"
        app:layout_constraintGuide_percent="0.8"
        android:orientation="vertical"/>

    <androidx.cardview.widget.CardView
        android:id="@+id/cardViewChatContainer"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:cardBackgroundColor="@android:color/transparent"
        app:cardElevation="0dp"
        app:layout_constraintEnd_toStartOf="@+id/guidelineForReceivedChat"
        app:cardPreventCornerOverlap="false"
        app:cardUseCompatPadding="true"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textViewDateStripe">

        <LinearLayout
            android:id="@+id/layoutChatContainer"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:paddingStart="8dp"
            android:paddingEnd="8dp"
            android:paddingTop="8dp"
            android:paddingBottom="5dp"
            android:layout_marginEnd="0dp"
            android:background="@drawable/bg_chat_corner_left"
            android:orientation="vertical">

            <TextView
                android:id="@+id/textViewMessageContent"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textSize="16sp"
                android:layout_gravity="start|center"
                android:gravity="start|center"
                android:textColor="@android:color/darker_gray"/>

            <TextView
                android:id="@+id/textViewMessageDate"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="end|bottom"
                android:gravity="end|bottom"
                android:textColor="#A8ADAF"
                android:textSize="12sp"
                android:layout_marginTop="5dp"
                app:layout_constraintBottom_toBottomOf="@+id/cardViewChatContainerReceived"
                app:layout_constraintStart_toEndOf="@+id/cardViewChatContainerReceived"
                tools:text="8:00" />

        </LinearLayout>

    </androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>

Adapter

 class AmityChatSDKMessagePagedDataAdapter :
        PagingDataAdapter<AmityMessage, RecyclerView.ViewHolder>(AmityChatSDKMessageListingPagedListDiffUtils) {}

As same code is working for PagedList in that only i have to change extended adapter as below

class AmityChatSDKMessageListAdapter :
    AmityMessageAdapter<RecyclerView.ViewHolder>(AmityChatSDKMessageListingDiffUtils) {}

Please let me know if anything required.

Hi @vmansuri ,

Thank you so much for the detail implementation.
We can reproduce the issue on our side and will further investigate and apply a fix.

In the meantime,
we recommend replacing “.getPagingData()” with

  1. “.query()” to continue using as PagedList
    or
  2. “.loader()” where you can explicitly handle pagination.
    For ex.,
val loader = messageRepository.getMessages(channelId)
            .stackFromEnd(stackFromEnd = true)
            .parentId(null)
            .build()
           .loader()

// add result to adapter
loader.getResult()
          .doOnNext {
               // submit list to adapter
          }
         .subscribe()

// load next page
loader.load().subscribe()