19

I have some weird issue with RecyclerView since I changed my app to load the data from Room database.

I have a screen (a Fragment) which displays a Profile for a user. Basically it's a GridLayout with the first item (row) displaying some info about the user and then for each row I'm displaying three images.

The code for the RecyclerView is :

private void initializeRecyclerView() {
    if (listAdapter == null) {
        listAdapter = new PhotosListAdapter(getActivity(), userProfileAccountId, false);
    }

    rvPhotosList.setNestedScrollingEnabled(true);
    rvPhotosList.getItemAnimator().setChangeDuration(0);

    GridLayoutManager layoutManager = new GridLayoutManager(getContext(), ProfileFragment.GRID_COLUMNS,
            LinearLayoutManager.VERTICAL, false);

    layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
        @Override
        public int getSpanSize(int position) {
            // 3 spans for Header, 1 for photos
            return listAdapter.isHeader(position) ? 3 : 1;
        }
    });

    rvPhotosList.setLayoutManager(layoutManager);

    int spacingInPixels = 1dp;
    rvPhotosList.addItemDecoration(new PaddingItemDecoration(GRID_COLUMNS, spacingInPixels, true));

    rvPhotosList.setAdapter(listAdapter);
}

and this is how I load data :

    compositeDisposable.add(
        repository.getAccount(accountId)
            .doOnNext(account -> {
                if (account != null && view != null) {
                    view.showCover(account.getCover());
                    view.showAccount(account);
                }
            })
            .flatMap(s -> repository.getUserPosts(accountId))
            .subscribe(posts -> {
                if (view != null) {
                    view.showPosts(posts);
                }
            }, throwable -> {}));

Both calls return a Flowable, either a Flowable<Account> or a Flowable<Post> where Account and Post are Room's Entity classes. The two methods showAccount() and showPosts() pass the previously mentioned entity classes to the adapter.

The problem is this : the moment the data are loaded it scrolls to the bottom of the screen (which is also the bottom of the RecyclerView).

I'm not sure why this happens. Is it because of Room's Flowable type?Cause previously when I was fetching the data from network and passing them to the adapter I didn't have this problem.

Edit : I'm using version 25.3.1 for RecyclerView

Edit 2 : This is how I'm updating my adapter class with Account and Post data :

public void addPhotos(List<Post> posts) {
    dataset.addAll(posts);
    notifyDataSetChanged();
}

public void addProfileItem(Account account) {
    this.account = account;
    notifyItemInserted(0);
}
Mes
  • 1,671
  • 3
  • 20
  • 36
  • 1
    It's already been answered by stackoverflow https://stackoverflow.com/questions/38949034/nested-recyclerview-scrolls-by-itself – Akhil Jan 25 '19 at 19:35

4 Answers4

36

Did you try this? Setting descendantFocusability property of parent RecyclerView to blocksDescendants.

What this will do is, it will no more focus on your dynamically loaded child views inside recycler view, as a result, the automatic scroll will not take place.

android:descendantFocusability="blocksDescendants"

Note: The property descendantFocusability can be used with other views as well like FrameLayout, RelativeLayout, etc. So if you set this property to your parent/root layout, it will no more scroll to bottom.

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Arpit J.
  • 1,108
  • 12
  • 20
1

If you have some initial items, that should be at the bottom after new items loaded, then you need to give them new ids, if you don't want to recycler scrolls to the bottom. It happens because the recycler remember that this items was visible to the user before update and after update he restore his state so that initial items at the bottom will be displayed

Azamat D
  • 21
  • 3
0

In my case this line was culprit,

GridLayoutManager gridLayoutManager = new GridLayoutManager(this, SPAN_COUNT, GridLayoutManager.VERTICAL, true);

Specifically , last parameter which is setting reverseLayout attribute to true. Make it false and RecyclerView doesn't scroll to bottom of screen.

Sushant
  • 440
  • 3
  • 8
  • As you could see from the question, the value was already false. Nevertheless, that's not a solution in the case you DO need the reverseLayout attribute set to true. – IIRed-DeathII Jul 12 '19 at 11:13
0

Although this questions is a bit old, seems like no answer is correct. I think what you need here is to listen to the Adapter changes and then scroll to the bottom on every detected change.

This is a working example of it

listAdapter?.registerAdapterDataObserver(object : AdapterDataObserver() {
    override fun onChanged() {
        rvPhotosList?.smoothScrollToPosition(listAdapter?.itemCount ?: 0)
    }
})
Diego Marcher
  • 378
  • 3
  • 7