![](/img/trans.png)
[英]How to prevent fragment to refresh recyclerview when after back from another fragment / save recyclerview position
[英]How to save and restore scrolling position of the RecyclerView in a fragment when coming back from other activity to the same fragment?
對版主的要求:這不是一個重復的問題,請閱讀以下信息。
在問這個問題之前,我已經嘗試了幾乎所有可用的解決方案,但沒有一個對我有用,有些導致崩潰,有些根本不起作用(我是初學者,可能我已經在我的代碼中做錯了什么,我不會責怪任何人在 SO 上可用的答案在我的情況下不起作用)。 下面是我的代碼,請看:
fragment_tab1.xml(包含recyclerview):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:layout_height="match_parent"
android:layout_width="match_parent"
android:background="#333333"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="96dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="42dp"
android:background="@color/colorPrimaryDark"
android:id="@+id/sort1"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/sort"
android:layout_marginLeft="10dp"
android:fontFamily="@font/quicksand"
android:textStyle="bold"
android:text="Sort by:"
android:textColor="#ffffff"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
style="@style/Widget.AppCompat.Button.Colored"
android:text="Oldest first"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/Widget.AppCompat.Button.Colored"
android:text="Newest first"/>
</LinearLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_below="@id/sort1"
android:clipToPadding="false"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:padding="5dp" />
</RelativeLayout>
</LinearLayout>
片段表1.java
public class tab1 extends Fragment {
RecyclerView mRecyclerView;
FirebaseDatabase mFirebaseDatabase;
DatabaseReference mRef;
LinearLayoutManager manager;
private static final String TAG = "tab1";
ProgressDialog progressDialog;
View rootView;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//Returning the layout file after inflating
//Change R.layout.tab1 in you classes
rootView = inflater.inflate(R.layout.fragment_tab1, container, false);
return rootView;
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mRecyclerView = (RecyclerView) rootView.findViewById(R.id.recycler_view);
manager = new LinearLayoutManager(getActivity());
mRecyclerView.setLayoutManager(manager);
mRecyclerView.setItemViewCacheSize(20);
mRecyclerView.setDrawingCacheEnabled(true);
mFirebaseDatabase = FirebaseDatabase.getInstance();
mRef = mFirebaseDatabase.getReference("memes");
mFirebaseDatabase.getInstance().getReference().keepSynced(true);
progressDialog = new ProgressDialog(getActivity());
progressDialog.setMessage("Please Wait");
progressDialog.show();
}
public void onStart() {
super.onStart();
FirebaseRecyclerAdapter<Model, ViewHolder> firebaseRecyclerAdapter =
new FirebaseRecyclerAdapter<Model, ViewHolder>(
Model.class,
R.layout.row2,
ViewHolder.class,
mRef
) {
@Override
protected void populateViewHolder(ViewHolder viewHolder, Model model, int position) {
viewHolder.setDetails(getActivity(), model.getTitle(), model.getDesc(), model.getImage());
progressDialog.cancel();
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
ViewHolder viewHolder = super.onCreateViewHolder(parent, viewType);
viewHolder.setOnClickListener(new ViewHolder.ClickListener(){
@Override
public void onItemClick(View view, int position){
//get data from firebase here
String mTitle = getItem(position).getTitle();
String mDesc= getItem(position).getDesc();
String mImage = getItem(position).getImage();
//pass this data to new activity
Intent intent = new Intent(view.getContext(), ArticleDetail.class);
intent.putExtra("title", mTitle);// put title
intent.putExtra("desc", mDesc);// put description
intent.putExtra("image", mImage); //put image urls
startActivity(intent);
}
@Override
public void onItemLongClick(View view, int position){
//TODO your own implementation on long item click
}
});
return viewHolder;
}
};
mRecyclerView.setAdapter(firebaseRecyclerAdapter);
}
@Override
public void onPause() {
super.onPause();
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
View firstChild = mRecyclerView.getChildAt(0);
int firstVisiblePosition = mRecyclerView.getChildAdapterPosition(firstChild);
int offset = firstChild.getTop();
Log.d(TAG, "Postition: " + firstVisiblePosition);
Log.d(TAG, "Offset: " + offset);
preferences.edit()
.putInt("position", firstVisiblePosition)
.putInt("offset", offset)
.apply();
}
@Override
public void onResume(){
super.onResume();
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
@Override
public void onViewStateRestored(@Nullable Bundle savedInstanceState) {
super.onViewStateRestored(savedInstanceState);
}
}
付出了這么多天,嘗試了很多解決方案,終於找到了解決我問題的可行方案,感謝https://stackoverflow.com/a/42563804/2128364
我已將工作解決方案移至另一種方法以使其在片段中工作。
也許這可以挽救某人的一天,這是它的工作原理:
您必須在 onPause 方法中保存狀態:
mBundleRecyclerViewState = new Bundle(); mListState = mRecyclerView.getLayoutManager().onSaveInstanceState(); mBundleRecyclerViewState.putParcelable(KEY_RECYCLER_STATE, mListState);
然后在 onResume 方法中恢復它:
if (mBundleRecyclerViewState != null) { new Handler().postDelayed(new Runnable() { @Override public void run() { mListState = mBundleRecyclerViewState.getParcelable(KEY_RECYCLER_STATE); mRecyclerView.getLayoutManager().onRestoreInstanceState(mListState); } }, 50); } mRecyclerView.setLayoutManager(staggeredGridLayoutManager);
如果您還沒有,請在build.gradle
添加recyclerView
依賴build.gradle
implementation "androidx.recyclerview:recyclerview:1.2.0"
不僅僅是在初始化列表適配器后設置stateRestorationPolicy
。
listAdapter = ListAdapter()
// Set scroll restore policy
listdapter.stateRestorationPolicy =
RecyclerView.Adapter.StateRestorationPolicy.PREVENT_WHEN_EMPTY
有關stateRestorationPolicy
和不同類型政策的更多信息, 請訪問本文
您應該使用此方法返回可見的第一個項目:
int findFirstVisibleItemPosition();
那么你必須在 onPause() 保存這個索引,當用戶返回時檢索並在 onResume() 設置它:
void scrollToPosition (int position)
好的,最后我想我得到了未來編碼人員的答案 將 On Create View 中的所有代碼保留在片段中,如果不嘗試通過在類中聲明所有變量而不是在本地方法中如何在創建視圖中獲取上下文,它將工作最多次數工作
如果有人介意使用靜態對象Bundle mBundleRecyclerViewState
接受它的答案,則可以改用ViewModel
。
public class MainViewModel extends ViewModel {
private static final String RECYCLER_VIEW_STATE = "recyclerViewState";
private final Bundle mRecyclerViewState;
public MainViewModel() {
mRecyclerViewState = new Bundle();
}
/**
* Back up RecyclerView's state to ViewModel in Fragment's onDestroyView
* or in Activity's onStop (or in somewhere else appropriate)
*
* @param layoutManager RecyclerView.LayoutManager object
*/
public void saveRecyclerViewState(RecyclerView.LayoutManager layoutManager) {
mRecyclerViewState.putParcelable(
RECYCLER_VIEW_STATE, layoutManager.onSaveInstanceState()
);
}
/**
* Restore backed up RecyclerView's state from ViewModel in onCreate
*
* @param layoutManager RecyclerView.LayoutManager object
*/
public void restoreRecyclerViewState(RecyclerView.LayoutManager layoutManager) {
layoutManager.onRestoreInstanceState(
mRecyclerViewState.getParcelable(RECYCLER_VIEW_STATE)
);
}
}
使用示例(在 Fragment 中):
private MainViewModel mViewModel;
private GridLayoutManager mLayoutManager;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mViewModel = new ViewModelProvider(requireActivity()).get(MainViewModel.class);
mLayoutManager = new GridLayoutManager(requireContext(), ITEMS_PER_ROW);
mViewModel.restoreRecyclerViewState(mLayoutManager);
}
@Override
public void onDestroyView() {
mViewModel.saveRecyclerViewState(mLayoutManager);
super.onDestroyView();
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.