[英]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以及具有此功能的应用程序示例
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,要求每次设置回收视图的数据,我建议视图模型更好的生命周期移交,使用LiveData或Stateflow中的视图模型来证明你的数据的完整性
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.