'RecyclerView is not going to the orignal starting position
Recently I have added saving and restoring functionality in my recycler view so when I navigate between different fragments the recycler view maintains its position when I come back but now there is an issue when I click the fragment again I think the recycler view should go to the top of the original starting position but no it is maintaining the same position and I have to go manually by scroll down(to go to the top)
Here is a screen recording
as you can see when I navigate from the Home Fragment
to Profile Fragment
and back again to the Home fragment
the position of the recycler view is maintained but if I click the Home
icon again RecyclerView
should go back to the top but it's not going eventually I have to manually do it
Here is my Code
Note:- if anyone wants more references for my code please tell me I will update the question
Home_Fragment.java // the implementation of saving and restoring the position is in the last so you can skip to the last if you want to
@SuppressLint("SourceLockedOrientationActivity")
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_home, container, false);
requireActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
MaterialToolbar materialToolbar = view.findViewById(R.id.toolbar);
materialToolbar.setOnMenuItemClickListener(toolbarItemClickListener);
postRecyclerView = view.findViewById(R.id.recyclerViewHome);
shimmerFrameLayout = view.findViewById(R.id.shimmerEffect);
// this is for one item per scroll
// SnapHelper snapHelper = new PagerSnapHelper();
// snapHelper.attachToRecyclerView(verticalRecyclerView);
postRecyclerView.setAdapter(postsAdapter);
// listState = savedInstanceState.getParcelable("ListState");
StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(1, StaggeredGridLayoutManager.VERTICAL);
postRecyclerView.setLayoutManager(
staggeredGridLayoutManager
);
postRecyclerView.setItemAnimator(null);
getData();
postRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
visibleItemCount = staggeredGridLayoutManager.getChildCount();
totalItemCount = staggeredGridLayoutManager.getItemCount();
int[] firstVisibleItems = null;
firstVisibleItems = staggeredGridLayoutManager.findFirstVisibleItemPositions(firstVisibleItems);
if (firstVisibleItems != null && firstVisibleItems.length > 0) {
pastVisibleItems = firstVisibleItems[0];
}
if (loading) {
if ((visibleItemCount + pastVisibleItems) >= totalItemCount) {
loading = false;
getData();
Log.d("tag", "LOAD NEXT ITEM");
}
}
}
});
// setupFirebaseAuth();
shimmerFrameLayout.startShimmer();
mUploads = new ArrayList<>();
postsAdapter = new PostAdapter_Home(getContext(), mUploads);
postRecyclerView.setAdapter(postsAdapter);
postRecyclerView.scrollToPosition(Home_Fragment.saved_position);
return view;
}
private void getData() {
databaseReference.addValueEventListener(new ValueEventListener() {
@SuppressLint("NotifyDataSetChanged")
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
if (snapshot.exists()) {
shimmerFrameLayout.stopShimmer();
shimmerFrameLayout.setVisibility(View.GONE);
postRecyclerView.setVisibility(View.VISIBLE);
mUploads.clear();
for (DataSnapshot dataSnapshot : snapshot.getChildren()) {
Upload upload = dataSnapshot.getValue(Upload.class);
assert upload != null;
upload.setmKey(dataSnapshot.getKey());
mUploads.add(upload);
}
}
postsAdapter.setUploads(mUploads);
//notify the adapter
postsAdapter.notifyDataSetChanged();
loading = true;
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
loading = true;
}
});
}
@Override
public void onPause() {
super.onPause();
mBundleRecyclerViewState = new Bundle();
mListState = postRecyclerView.getLayoutManager().onSaveInstanceState();
mBundleRecyclerViewState.putParcelable(KEY_RECYCLER_STATE, mListState);
}
@Override
public void onResume() {
super.onResume();
if (mBundleRecyclerViewState != null) {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mListState = mBundleRecyclerViewState.getParcelable(KEY_RECYCLER_STATE);
postRecyclerView.getLayoutManager().onRestoreInstanceState(mListState);
}
}, 50);
}
}
public void onStop() {
super.onStop();
// if (mAuthListener != null) {
// mAuth.removeAuthStateListener(mAuthListener);
// }
}
}
Solution 1:[1]
You can use StateRestorationPolicy for saving & restoring the recycler view state https://medium.com/androiddevelopers/restore-recyclerview-scroll-position-a8fbdc9a9334
Just need to add the dependency in app.gradle
implementation "androidx.recyclerview:recyclerview:1.2.1"
and add the code while setting recycler view adapter
postsAdapter.stateRestorationPolicy = PREVENT_WHEN_EMPTY
Solution 2:[2]
I see that when your method 'onScrolled' hits 'loading', it calls getData() method which adds a new Listener instead of a simple method execution. It leads to such thing that every time the data set is changed, the event is fired, then accumulated event handlers will execute the same code. More you scroll is more times you get the code executed. As this code is executed on the UI Thread it will cause performance issues. May be this multiple code execution is the source of the issue you described.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Naveen Verma |
Solution 2 | Dharman |