Sorry for my poor English.
I want the exact position. And after the activity/fragment has been destroyed (no matter I destroy it or the System destroys it), I reopen the activity/fragment, the RecyclerView
can also as the same position as it is been destroyed.
The "same" not means "the item position", because maybe the item just display partly last time.
I want to restore the exact same position.
I have tried some ways below, but no one is perfect.
Someone can help?
1.First way.
I use onScrolled
to calculate the scroll exact position, when the scroll stop, save the position. When spinner changes the dataset or fragment onCreat, restore the position of the chosen dataset. Some datasets may have many many rows.
It can save and restore after the app is destroyed, but there may be too much calculate ?
It will cause
Skipped 60 frames! The application may be doing too much work on its main thread. attempt to finish an input event but the input event receiver has already been disposed. android total arena pages for jit.
And if scrollY
is huge, like 111111
, when open the fragment, the RecyclerView will first show the list begin from the first item, and after some delay, it scrolls to the scrollY
position.
How to make it no delay ?
recyclerView.addOnScrollListener(new OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, final int dy) {
super.onScrolled(recyclerView, dx, dy);
handler.post(new Runnable() {
@Override
public void run() {
if (isTableSwitched) {
scrollY = 0;
isTableSwitched = false;
}
scrollY = scrollY + dy;
Log.i("dy——scrollY——table", String.valueOf(dy) + "——" + String.valueOf(scrollY) + tableName);
}
});
}
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
switch (newState) {
case RecyclerView.SCROLL_STATE_IDLE:
saveRecyclerPosition(tableName, scrollY);
break;
case RecyclerView.SCROLL_STATE_DRAGGING:
break;
case RecyclerView.SCROLL_STATE_SETTLING:
break;
}
}
});
public void saveRecyclerPosition(String tableName, int y) {
prefEditorSettings.putInt(KEY_SCROLL_Y + tableName, y);
prefEditorSettings.commit();
}
public void restoreRecyclerViewState(final String tableName) {
handler.post(new Runnable() {
@Override
public void run() {
recyclerView.scrollBy(0, prefSettings.getInt(KEY_SCROLL_Y + tableName, 0));
}
});
}
//use Spinner to choose dataset
spnWordbook.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
isTableSwitched = true;
tableName= parent.getItemAtPosition(position).toString();
prefEditorSettings.putString(KEY_SPINNER_SELECTED_TABLENAME, tableName);
prefEditorSettings.commit();
wordsList = WordsManager.getWordsList(tableName);
wordCardAdapter.updateList(wordsList);
restoreRecyclerViewState(tableName);
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
2.Second way.
This runs perfectly, but it can only work in the fragment lifecycle.
I try to use ObjectOutputStream
and ObjectInputStream
to save and restore the HashMap
, but it doesn't work.
How to save it in memory ?
private HashMap <String, Parcelable> hmRecyclerViewState = new HashMap<String, Parcelable>();
public void saveRecyclerPosition(String tableName) {
recyclerViewState = recyclerView.getLayoutManager().onSaveInstanceState();
hmRecyclerViewState.put(tableName, recyclerViewState);
}
public void restoreRecyclerViewState(final String tableName) {
if ( hmRecyclerViewState.get(tableName) != null) {
recyclerViewState = hmRecyclerViewState.get(tableName);
recyclerView.getLayoutManager().onRestoreInstanceState(recyclerViewState);
recyclerViewState = null;
}
3.Third way.
I change the second way, use Bundle
instead of HashMap
, but it has the same question, doesn't work when out of the fragment lifecycle.
I use manually serialize/deserialize android bundle to save bundle
in memory, but when restoring it, it doesn't get the valid bundle
.
======================================================================= The solution
Thanks, everyone!
Finally I solve this problem, you can see it in my code, just see these 2 methods: saveRecyclerViewPosition and restoreWordRecyclerViewPosition .