3

After the adapter submitList to the DiffUtil, onBindViewHolder is called and for some reason it always scroll the list to the top.

I tried every single one of the answers in SO regarding autoscroll on updating list in the recyclerview but can't solve the issue.

i.e.

RecyclerView: Disable scrolling caused by change in focus

RecyclerView scrolls to top on notifyDataSetChanged in chat screen

android notifyItemRangeInserted disable autoscroll

etc

Here is my adapter:

init {
    setHasStableIds(true)
}

private val currentDiffer = AsyncListDiffer<Item>(this, MyDiffUtil())

...

override fun setHasStableIds(hasStableIds: Boolean) {
    super.setHasStableIds(true)
}

override fun getItemCount(): Int {
    return currentDiffer.currentList.size
}

override fun getItemId(position: Int): Long = currentDiffer.currentList[position].name.hashCode().toLong()
override fun getItemViewType(position: Int) = position

override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
    super.onAttachedToRecyclerView(recyclerView)
}

override fun onBindViewHolder(holder: CurrentListViewHolder, position: Int) {
    holder.bindView(position, activity, currentDiffer.currentList[position], onCurrencyListener)
}


override fun onViewRecycled(holder: CurrentListViewHolder) {
    holder.unbindView()
    super.onViewRecycled(holder)
}

fun setData(list: LinkedList<Item>) {
    val newList: LinkedList<Item> = LinkedList()
    newList.addAll(list)

    currentDiffer.submitList(newList.toList())
}

So after every new submit of the list, no matter what is the current position, onBindViewHolder is called and before it does anything the list is scrolled to 0 position like the scrollToPosition is called.

EDIT:

private fun setView() {

  currentListAdapter = CurrentListAdapter()
  with(currenciesRv) {
        layoutManager = LinearLayoutManager(context)
        adapter = currentListAdapter
 }

layout:

      <RelativeLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content">

        <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/listRv"
                android:layout_width="match_parent"
                android:layout_height="match_parent"/>

     </RelativeLayout>

item:

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" 
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/itemLayout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

<de.hdodenhof.circleimageview.CircleImageView
        android:id="@+id/itemIvFlag"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_marginTop="30dp"
        android:layout_marginStart="15dp"
        android:layout_alignParentStart="true"
        android:layout_centerVertical="true"/>

<LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toEndOf="@id/itemIvFlag"
        android:orientation="vertical"
        android:layout_centerVertical="true"
        android:layout_marginTop="10dp">

    <TextView
            android:id="@+id/itemTvISO"
            android:layout_marginStart="10dp"
            android:textStyle="bold"
            tools:text="@string/dummy_number"
            android:textSize="16sp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>

    <TextView
            android:id="@+id/itemTvName"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:layout_marginStart="10dp"
            android:textSize="14sp"
            tools:text="@string/dummy_number"/>

</LinearLayout>


<EditText
        android:id="@+id/itemEtAmount"
        android:layout_alignParentEnd="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_marginEnd="15dp"
        tools:text="@string/dummy_number"
        android:inputType="numberDecimal"
        android:enabled="false"
        android:textColor="@drawable/et_disabled_color"
        android:imeOptions="actionDone"
        android:maxLines="1"
        android:singleLine="true"/>

 </RelativeLayout>
tompadre
  • 789
  • 7
  • 20
  • Does item at position 0 move? `LinearLayoutManager` aggressively follows it by default – Pawel Aug 14 '19 at 13:16
  • post the code of `CurrentListViewHolder.kt` – Santanu Sur Aug 14 '19 at 13:20
  • @Pawel at this point no. I have clickListener on the list which sets the clicked item to the 0 but that is expected behaviour and works fine. Otherwise, every few seconds the list is refreshed from the server and if the list is scrolled down, onBindViewHolder scrolls it back to 0 – tompadre Aug 14 '19 at 13:25
  • @SantanuSur ViewHolder isn't important really because like I wrote the list is scrolled on the start of the onBindViewholder meaning that even if the binding viewHolder is commented/deleted this behaviour occur. – tompadre Aug 14 '19 at 13:28
  • @tompadre Maybe is issue with focus, with EditText, try to comment out EditText in your recycler View item. – mmmatey Aug 20 '19 at 07:17
  • @mmmatey Thanks for the answer. That was also one of my first thoughts but unfortunately something else is messing with the scrolling and/or focus :/ – tompadre Aug 20 '19 at 07:23
  • 1
    @tompadre next thing which you should tell us, is Item class "data" class or did you override hashCode and equals for comparing items in diffUtils? Can you share also MyDiffUtil? – mmmatey Aug 20 '19 at 07:35
  • @mmmatey Hvala kolega za fresh pair of eyes! – tompadre Aug 20 '19 at 08:16

2 Answers2

2

The problem was with my DiffUtil. I was reckless and sloppy and had wrong/basically the same values on both areItemsTheSame and areContentsTheSame so diffUtil saw no difference between them meaning that every new content was the same as the new item.

tompadre
  • 789
  • 7
  • 20
1

Post override method for comparing submitted list by DiffUtil. I faced similar problem (my problem was RecycleView keeping focus on list_item_network_state, which was displaying loading views). From comments under your post "every few seconds the list is refreshed from the server and if the list is scrolled down, onBindViewHolder scrolls it back to 0", so when data is getting updated and it contains same items you want to have focus on the focused element from the old list?

a bit hard to find a solution for your problem (not enough info) I think problem is not on yours adapter.

Also an advise to use ListAdapter it has DiffUtil.ItemCallback in itself.

Update So if you don't have anything in the onBIndViewHolder it still scrolls to the top, that mean the problem is not there. The problem lies in submitting new list (as DiffUtil "it used to calculate updates for a RecyclerView Adapter."). As during comparing it decides where to delete/update/add an item. It possible there is a problem (it's my assumption on info you provided, add more code to your question if it's possible). Check methods as areItemsTheSame() (it must compare id of items for example) and after it calls areContentsTheSame() so it checks what have been changed.

mr.kostua
  • 619
  • 5
  • 11
  • Thanks for the answer. Yes, you understood correctly. I'm trying to update items without losing focus/recreating it and scrolling to the position 0. Number of items is always the same, only some of the data in the items is changing but is changing in the every item in the list. But like I wrote, even if I don't have anything in the onBindViewHolder, after submitList is called, list is scrolled to the top. – tompadre Aug 14 '19 at 14:20
  • @tompadre :) I have updated my answer. Still it's not enough info to solve the problem, as I think it's lies not in the adapter. – mr.kostua Aug 15 '19 at 12:20
  • 1
    the rest of the code is plain simple and straightforward so I don't see where the issue can be but I updated my question anyway. DiffUtil works fine afaik and I migrated adapter to the ListAdapter but the mistery remains – tompadre Aug 20 '19 at 07:08