简体   繁体   English

从另一个片段/保存recyclerview位置返回后,如何防止片段刷新recyclerview

[英]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在这部分中,我尝试在我的应用程序中添加一项功能并解决一个问题,我想保存 recyclerview 位置,因此当单击并导航到详细信息片段并单击返回时,这应该回到相同的位置,这里的问题是我点击返回我看到项目重叠,大约有 8 个项目,它从下一个列表位置开始,当我寻找这个问题的解决方案时,我找到了这个答案然后我决定单独添加 recyclerview 的依赖项implementation "androidx.recyclerview:recyclerview:1.2.1"使用此功能

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

but it doesn't work, the next GIF describe the problem但它不起作用,下一个GIF描述问题

recyclerview position problem recyclerview位置问题

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 .尝试在onCreate而不是onViewCreated初始化适配器然后您可以在onViewCreated recyclerview 上设置适配器。

Also use try using LiveData Event Wrapper : https://stackoverflow.com/a/51762972/9854554也可以尝试使用 LiveData 事件包装器: 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)它会阻止 livedata 观察者在片段恢复时再次获取数据(当我们再次订阅 livedata 时)

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在另一个片段中更改数据时如何刷新一个片段中的RecyclerView - How to refresh RecyclerView in one fragment when data changed in another fragment 如何从同一片段中的其他 recyclerview 适配器刷新 recyclerview 适配器 - How to refresh recyclerview adapter from other recyclerview adapter in same fragment 如何在更改片段上保存片段回收视图数据? - How to save Fragment recyclerview data on change fragment? 在片段中滚动RecyclerView时防止FAB下降 - Prevent FAB from going down when scrolling in RecyclerView in fragment 当其他片段中的数据更改时,如何刷新recyclerview适配器? - How to refresh recyclerview adapter when data changes in other fragment? SearchView 与 RecyclerView(应用程序在返回包含 recyclerview 的片段时关闭) - SearchView with RecyclerView (App closes when back to fragment which contains the recyclerview) 如何在viewpager的片段中保存recyclerview的状态? - How to save state of recyclerview in fragment in viewpager? 从另一个片段重置RecyclerView适配器 - Reset RecyclerView adapter from another Fragment Android-如何从ViewPager中的另一个片段更新我的Recyclerview? - Android - How to update my recyclerview from another fragment in a viewpager? 将数据从 RecyclerView 传递到片段中的另一个 - Pass data from RecyclerView to another in fragment
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM