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 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
- The parameters given to the SDK API for message query
- LayoutManager properties such as “stackFromEnd” and “reverseLayout”
- Properties of recyclerview in XML file
- 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.
- 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()
}
- 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)
}
}
})
}
- 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" />
- 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
- “.query()” to continue using as PagedList
or
- “.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()