简体   繁体   中英

How to prevent fragment to refresh recyclerview when after back from another fragment / save recyclerview position

In this part I try to add one feature in my app and fix one problem, I would like to save the recyclerview position so when click and navigate to details fragment and click back, this should back to the same position, the issue here is when I click back I see the items overlapping, there are about 8 items and it starts from next list position, while I searching for the solution of this issue, I found this answer then I decided to add the dependencies of recyclerview separately implementation "androidx.recyclerview:recyclerview:1.2.1" to use this feature

adapter.setStateRestorationPolicy(RecyclerView.Adapter.StateRestorationPolicy.PREVENT_WHEN_EMPTY);

but it doesn't work, the next GIF describe the problem

recyclerview position problem

and this example of the app with this feature

Target

HomeFragment

@AndroidEntryPoint
public class HomeFragment extends Fragment {

    private FragmentHomeBinding binding;
    private PostViewModel postViewModel;
    public static final String TAG = "HomeFragment";
    private PostAdapter adapter;
    private List<Item> itemArrayList;
    private GridLayoutManager titleLayoutManager, gridLayoutManager;
    WrapContentLinearLayoutManager layoutManager;

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        binding.homeRecyclerView.addOnItemTouchListener(new RecyclerItemClickListener(requireContext(),
                binding.homeRecyclerView, new RecyclerItemClickListener.OnItemClickListener() {
            @Override
            public void onItemClick(View view, int position) {

                Item item = itemArrayList.get(position);

                if (Objects.requireNonNull
                        (Navigation.findNavController(requireView())
                                .getCurrentDestination()).getId() == R.id.nav_home) {
                    Navigation.findNavController(requireView())
                            .navigate(HomeFragmentDirections.actionNavHomeToDetailsFragment(item));
                }
            }

            @Override
            public void onLongItemClick(View view, int position) {

            }
        }));
    }


    public View onCreateView(@NonNull LayoutInflater inflater,
                             @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {


        binding = FragmentHomeBinding.inflate(inflater, container, false);
        setHasOptionsMenu(true);

        postViewModel = new ViewModelProvider(this).get(PostViewModel.class);
        postViewModel.finalURL.setValue(Constants.getBaseUrl() + "?key=" + Constants.getKEY());
        itemArrayList = new ArrayList<>();
        adapter = new PostAdapter(getContext(), itemArrayList, this, postViewModel);

        layoutManager = new WrapContentLinearLayoutManager(requireContext(),
                LinearLayoutManager.VERTICAL, false);
        titleLayoutManager = new GridLayoutManager(getContext(), 2);
        gridLayoutManager = new GridLayoutManager(getContext(), 3);


//        binding.homeRecyclerView.setAdapter(adapter);
        binding.shimmerLayout.setVisibility(View.VISIBLE);
        binding.homeRecyclerView.setVisibility(View.INVISIBLE);

        adapter.setStateRestorationPolicy(RecyclerView.Adapter.StateRestorationPolicy.PREVENT_WHEN_EMPTY);


        postViewModel.recyclerViewLayoutMT.observe(getViewLifecycleOwner(), layout -> {
            Log.w(TAG, "getSavedLayout: called");
            switch (layout) {
                case "cardLayout":
                    binding.loadMoreBtn.setVisibility(View.VISIBLE);
                    binding.homeRecyclerView.setLayoutManager(layoutManager);
                    binding.homeRecyclerView.setAdapter(adapter);
                    adapter.setViewType(0);

                    break;
                case "cardMagazineLayout":
                    binding.loadMoreBtn.setVisibility(View.VISIBLE);
                    binding.homeRecyclerView.setLayoutManager(layoutManager);
                    binding.homeRecyclerView.setAdapter(adapter);
                    adapter.setViewType(1);
                    break;
                case "titleLayout":
                    binding.loadMoreBtn.setVisibility(View.GONE);
                    binding.homeRecyclerView.setLayoutManager(titleLayoutManager);
                    binding.homeRecyclerView.setAdapter(adapter);
                    adapter.setViewType(2);
                    break;
                case "gridLayout":
                    binding.loadMoreBtn.setVisibility(View.GONE);
                    binding.homeRecyclerView.setLayoutManager(gridLayoutManager);
                    binding.homeRecyclerView.setAdapter(adapter);
                    adapter.setViewType(3);
            }
        });


        if (Utils.hasNetworkAccess(requireContext())) {

            postViewModel.getPosts();

            postViewModel.postListMutableLiveData.observe(getViewLifecycleOwner(), postList -> {
                itemArrayList.addAll(postList.getItems());
                binding.shimmerLayout.stopShimmer();
                binding.shimmerLayout.setVisibility(View.GONE);
                binding.homeRecyclerView.setVisibility(View.VISIBLE);
                adapter.notifyDataSetChanged();

                Log.e(TAG, "ItemsArrayList :" + itemArrayList.get(0).getTitle());

            });


        } else {

            binding.shimmerLayout.setVisibility(View.VISIBLE);
//            binding.shimmerLayout.startShimmer();


            if (postViewModel.getAllItemsFromDataBase == null) {

                noInternetConnectionLayout();

            } else {
//                Log.e(TAG, "RoomDB Items size :" + itemsDatabase.itemDAO().getAlItems());

                binding.shimmerLayout.stopShimmer();
                binding.shimmerLayout.setVisibility(View.GONE);
                binding.emptyView.setVisibility(View.GONE);
                binding.homeRecyclerView.setVisibility(View.VISIBLE);
                postViewModel.getAllItemsFromDataBase.observe(getViewLifecycleOwner(), items -> {
                    if (items.isEmpty()) {
                        noInternetConnectionLayout();
                    } else {
                        binding.loadMoreBtn.setVisibility(View.GONE);
                        itemArrayList.addAll(items);
                        adapter.notifyDataSetChanged();
                    }
                });

            }
        }

        postViewModel.errorCode.observe(getViewLifecycleOwner(), errorCode -> {
            if (errorCode == 400) {
                Snackbar.make(requireView(), R.string.lastPost, Snackbar.LENGTH_LONG).show();
            } else {
                binding.homeRecyclerView.setVisibility(View.INVISIBLE);
                binding.emptyView.setVisibility(View.VISIBLE);
            }
        });

        binding.loadMoreBtn.setOnClickListener(view -> {
            AlertDialog dialog = Utils.setProgressDialog(requireContext());

            postViewModel.isLoading.observe(getViewLifecycleOwner(), isLoading -> {
                if (isLoading) {
                    dialog.show();
                } else {
                    dialog.dismiss();
                }
            });

            if (Utils.hasNetworkAccess(requireContext())) {
                postViewModel.getPosts();
//                Log.w(TAG, "loadMoreBtn: " + dialog.isShowing());
            } else {
                postViewModel.isLoading.postValue(true);
                postViewModel.getAllItemsFromDataBase.getValue();
                postViewModel.isLoading.postValue(false);
            }

        });

        return binding.getRoot();

    }

    private void noInternetConnectionLayout() {
        binding.shimmerLayout.stopShimmer();
        binding.shimmerLayout.setVisibility(View.GONE);
        binding.homeRecyclerView.setVisibility(View.GONE);
        binding.emptyView.setVisibility(View.VISIBLE);
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        itemArrayList.clear();
        binding = null;
    }


    @Override
    public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {

        inflater.inflate(R.menu.main, menu);
        super.onCreateOptionsMenu(menu, inflater);

        SearchManager searchManager = (SearchManager) requireContext().getSystemService(Context.SEARCH_SERVICE);
        SearchView searchView = (SearchView) menu.findItem(R.id.app_bar_search).getActionView();
        searchView.setSearchableInfo(searchManager.getSearchableInfo(requireActivity().getComponentName()));
        searchView.setQueryHint(getResources().getString(R.string.searchForPosts));

        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String keyword) {
                if (keyword.isEmpty()) {
                    Snackbar.make(requireView(), "please enter keyword to search", Snackbar.LENGTH_SHORT).show();
                }
                if (Utils.hasNetworkAccess(requireContext())) {
                    itemArrayList.clear();
                    postViewModel.getItemsBySearch(keyword);
                    adapter.notifyDataSetChanged();
                } else {
                    postViewModel.getItemsBySearchInDB(keyword);
                    postViewModel.getItemsBySearchMT.observe(getViewLifecycleOwner(), items ->
                            {
                                Log.d(TAG, "onQueryTextSubmit database called");
                                itemArrayList.clear();
                                itemArrayList.addAll(items);
                                adapter.notifyDataSetChanged();
                            }
                    );
                }
                return false;
            }

            @Override
            public boolean onQueryTextChange(String newText) {
                return false;
            }
        });


        searchView.setOnCloseListener(() -> {

            if (Utils.hasNetworkAccess(requireContext())) {
                Log.d(TAG, "setOnCloseListener: called");
                itemArrayList.clear();
                binding.emptyView.setVisibility(View.GONE);
                binding.homeRecyclerView.setVisibility(View.VISIBLE);
                postViewModel.getPosts();
                adapter.notifyDataSetChanged();
            } else {
                Log.d(TAG, "setOnCloseListener: called");
                binding.emptyView.setVisibility(View.GONE);
                binding.homeRecyclerView.setVisibility(View.VISIBLE);
                postViewModel.getAllItemsFromDataBase.observe(getViewLifecycleOwner(), items ->
                        {
                            itemArrayList.addAll(items);
                            adapter.notifyDataSetChanged();
                        }
                );
            }
            return false;
        });


        postViewModel.searchError.observe(getViewLifecycleOwner(), searchError -> {
            if (searchError) {
                Toast.makeText(requireContext(),
                        "There's no posts with this keyword", Toast.LENGTH_LONG).show();
            }
        });


    }

    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {

        if (item.getItemId() == R.id.change_layout) {
            changeAndSaveLayout();
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

Try initializing the adapter in onCreate instead of onViewCreated Then you can set the adapter on recyclerview in onViewCreated .

Also use try using LiveData Event Wrapper : https://stackoverflow.com/a/51762972/9854554

It will prevent livedata observer from getting data again on fragment resume (when we subscribe again on the livedata)

您在onViewCreated,要求每次设置回收视图的数据,我建议视图模型更好的生命周期移交,使用LiveDataStateflow中的视图模型来证明你的数据的完整性

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM