gpt4 book ai didi

java - 从另一个 fragment 返回后如何防止 fragment 刷新recyclerview/保存recyclerview位置

转载 作者:行者123 更新时间:2023-12-04 23:44:40 28 4
gpt4 key购买 nike

在这部分我尝试在我的应用程序中添加一项功能并解决一个问题,我想保存 recyclerview 位置所以当点击并导航到详细信息 fragment 并点击返回时,这应该回到相同的位置,问题这是当我单击返回时,我看到项目重叠,大约有 8 个项目,它从下一个列表位置开始,在我搜索此问题的解决方案时,我发现了这个 answer然后我决定单独添加recyclerview的依赖implementation "androidx.recyclerview:recyclerview:1.2.1"来使用这个特性

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

但是不行,下一张GIF说明问题

recyclerview position problem

以及这个具有此功能的应用示例

Target

首页 fragment

@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);
}

ViewModel

@HiltViewModel
public class PostViewModel extends ViewModel {

public static final String TAG = "PostViewModel";


private final com.blogspot.abtallaldigital.data.Repository repository;
public final MutableLiveData<PostList> postListMutableLiveData = new MutableLiveData<>();
public final MutableLiveData<String> finalURL = new MutableLiveData<>();
public final MutableLiveData<String> token = new MutableLiveData<>();
public final MutableLiveData<String> label = new MutableLiveData<>();
public final MutableLiveData<Integer> errorCode = new MutableLiveData<>();
public final MutableLiveData<Boolean> searchError = new MutableLiveData<>();
public final LiveData<List<Item>> getAllItemsFromDataBase;
public final MutableLiveData<List<Item>>
getItemsBySearchMT = new MutableLiveData<>();
public final MutableLiveData<Boolean> isLoading = new MutableLiveData<>();
public final MutableLiveData<String> recyclerViewLayoutMT = new MutableLiveData<>();
private final Utils.DataStoreRepository dataStoreRepository;
public final MutableLiveData<Integer> currentDestination = new MutableLiveData<>();


// public MutableLiveData<Boolean> ifAnythingWrongHappened = new MutableLiveData<>();

@Inject
public PostViewModel(Repository repository, Utils.DataStoreRepository dataStoreRepository) {
this.repository = repository;
getAllItemsFromDataBase = repository.localDataSource.getAllItems();
this.dataStoreRepository = dataStoreRepository;
dataStoreRepository.readLayoutFlow
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new FlowableSubscriber<String>() {
@Override
public void onSubscribe(@NonNull Subscription s) {
s.request(Long.MAX_VALUE);
}

@Override
public void onNext(String layout) {
if (layout != null) {
recyclerViewLayoutMT.setValue(layout);
}
}

@Override
public void onError(Throwable t) {
Log.e(TAG, "onError: " + t.getMessage());
Log.e(TAG, "onError: " + t.getCause());
}

@Override
public void onComplete() {

}
});

dataStoreRepository.readCurrentDestination
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.firstOrError().subscribeWith(new SingleObserver<Integer>() {
@Override
public void onSubscribe(@NonNull Disposable d) {

}

@Override
public void onSuccess(@NonNull Integer destination) {
currentDestination.setValue(destination);
}

@Override
public void onError(@NonNull Throwable e) {
Log.e(TAG, "onError: " + e.getMessage());
}
});

}

public void saveRecyclerViewLayout(String layout) {
dataStoreRepository.saveRecyclerViewLayout("recyclerViewLayout", layout);
}

public void saveCurrentDestination(int currentDestination) {
dataStoreRepository
.saveCurrentDestination("CURRENT_DESTINATION", currentDestination);
}


// @Override
// protected void onCleared() {
// super.onCleared();
// postListMutableLiveData.setValue(null);
// finalURL.setValue(null);
// token.setValue(null);
// }

public void getPosts() {
Log.e(TAG, finalURL.getValue());

isLoading.setValue(true);
repository.remoteDataSource.getPostList(finalURL.getValue())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Response<PostList>>() {
@Override
public void onSubscribe(@NonNull Disposable d) {

}

@Override
public void onNext(@NonNull Response<PostList> postListResponse) {

if (postListResponse.isSuccessful()) {
if (postListResponse.body() != null
&& postListResponse.body().getNextPageToken() != null) {
Log.e(TAG, postListResponse.body().getNextPageToken());
token.setValue(postListResponse.body().getNextPageToken());
isLoading.setValue(false);
}
postListMutableLiveData.setValue(postListResponse.body());

for (int i = 0; i < postListResponse.body().getItems().size(); i++) {
repository.localDataSource.insertItem(postListResponse.body()
.getItems().get(i))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new CompletableObserver() {
@Override
public void onSubscribe(@NonNull Disposable d) {

}

@Override
public void onComplete() {

}

@Override
public void onError(@NonNull Throwable e) {

}
});
}

finalURL.setValue(finalURL.getValue() + "&pageToken=" + token.getValue());
} else {
isLoading.setValue(false);
errorCode.setValue(postListResponse.code());
Log.e(TAG, "onNext: " + postListResponse.code());
Log.e(TAG, "onNext: " + postListResponse.errorBody());
}
}

@Override
public void onError(@NonNull Throwable e) {
isLoading.setValue(false);
Log.e(TAG, e.getMessage() + e.getCause());
// ifAnythingWrongHappened.setValue(true);
if (e instanceof HttpException) {
errorCode.setValue(((HttpException) e).code());
}
}

@Override
public void onComplete() {

}
});

}


public void getPostListByLabel() {

isLoading.setValue(true);
Log.e(TAG, finalURL.getValue());

repository.remoteDataSource.getPostListByLabel(finalURL.getValue())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Response<com.blogspot.abtallaldigital.pojo.PostList>>() {
@Override
public void onSubscribe(@NonNull Disposable d) {

}

@Override
public void onNext(@NonNull Response<com.blogspot.abtallaldigital.pojo.PostList> postListResponse) {
if (postListResponse.isSuccessful()) {
if (postListResponse.body() != null) {
// Log.e(TAG, postListResponse.body().getNextPageToken());
token.setValue(postListResponse.body().getNextPageToken());
}
postListMutableLiveData.setValue(postListResponse.body());
isLoading.setValue(false);
finalURL.postValue(Constants.getBaseUrlPostsByLabel()
+ "posts?labels=" + label.getValue() + "&pageToken="
+ token.getValue()
+ "&key=" + Constants.getKEY());
} else {
isLoading.setValue(false);
errorCode.setValue(postListResponse.code());
Log.e(TAG, "onNext: " + postListResponse.code());
Log.e(TAG, "onNext: " + postListResponse.errorBody());
}
}

@Override
public void onError(@NonNull Throwable e) {
isLoading.setValue(false);
Log.e(TAG, e.getMessage() + e.getCause());
if (e instanceof HttpException) {
errorCode.setValue(((HttpException) e).code());
}
}

@Override
public void onComplete() {

}
});

}

public void getItemsBySearch(String keyword) {

isLoading.setValue(true);
searchError.setValue(false);

String url = Constants.getBaseUrl() +
"search?q=" + keyword + "&key=" + Constants.getKEY();

Log.e(TAG, "getItemsBySearch: " + url);

repository.remoteDataSource.getPostListBySearch(url)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Response<com.blogspot.abtallaldigital.pojo.PostList>>() {
@Override
public void onSubscribe(@NonNull Disposable d) {

}

@Override
public void onNext(@NonNull Response<PostList> postListResponse) {

if (postListResponse.isSuccessful()) {
if (postListResponse.body() != null
&& postListResponse.body().getNextPageToken() != null) {
Log.e(TAG, postListResponse.body().getNextPageToken());
token.setValue(postListResponse.body().getNextPageToken());
isLoading.setValue(false);
}
postListMutableLiveData.setValue(postListResponse.body());
} else {
isLoading.setValue(false);
searchError.setValue(true);
Log.e(TAG, "onNext: list is null");
}
}

@Override
public void onError(@NonNull Throwable e) {
isLoading.setValue(false);
Log.e(TAG, e.getMessage() + e.getCause());
// ifAnythingWrongHappened.setValue(true);
if (e instanceof HttpException) {
errorCode.setValue(((HttpException) e).code());
}
}

@Override
public void onComplete() {

}
});

}

public void getItemsBySearchInDB(String keyword) {
Log.d(TAG, "getItemsBySearchInDB: called");
repository.localDataSource.getItemsBySearch(keyword)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<List<com.blogspot.abtallaldigital.pojo.Item>>() {
@Override
public void onSubscribe(@NonNull Disposable d) {

}

@Override
public void onNext(@NonNull List<Item> items) {
if (items.isEmpty()) {
searchError.setValue(true);
Log.e(TAG, "onNext: list is empty");
} else {
getItemsBySearchMT.setValue(items);
Log.d(TAG, "onNext: " + items.size());
}
}

@Override
public void onError(@NonNull Throwable e) {
searchError.setValue(true);
}

@Override
public void onComplete() {

}
});

}

public void insertFavorites(FavoritesEntity favoritesEntity) {
repository.localDataSource.insertFavorites(favoritesEntity)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new CompletableObserver() {
@Override
public void onSubscribe(@NonNull Disposable d) {

}

@Override
public void onComplete() {

}

@Override
public void onError(@NonNull Throwable e) {
Log.e(TAG, "onError: " + e.getMessage());
}
});
}

public LiveData<List<FavoritesEntity>> getAllFavorites() {
return repository.localDataSource.getAllFavorites();
}

public void deleteFavoritePost(FavoritesEntity favoritesEntity) {
repository.localDataSource.deleteFavorite(favoritesEntity);
}

public void deleteAllFavorites() {
repository.localDataSource.deleteAllFavorites()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new CompletableObserver() {
@Override
public void onSubscribe(@NonNull Disposable d) {

}

@Override
public void onComplete() {

}

@Override
public void onError(@NonNull Throwable e) {
Log.e(TAG, "onError: " + e.getMessage());
}
});


}


}

最佳答案

尝试在 onCreate 而不是 onViewCreated 中初始化适配器然后,您可以在 onViewCreated 中的 recyclerview 上设置适配器。

也可以尝试使用 LiveData Event Wrapper : https://stackoverflow.com/a/51762972/9854554

Java 中的 LiveData 事件包装器:https://stackoverflow.com/a/56072658

它将阻止 livedata 观察者在 fragment 恢复上再次获取数据(当我们再次订阅 livedata 时)

关于java - 从另一个 fragment 返回后如何防止 fragment 刷新recyclerview/保存recyclerview位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69950970/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com