【发布时间】:2015-09-12 09:32:30
【问题描述】:
对不起,我的英语不好。
我想要确切的位置。而在activity/fragment被destroyed之后(不管是我销毁还是系统销毁),我重新打开activity/fragment,RecyclerView也可以是与被销毁的位置相同。
“相同”并不是“项目位置”,因为可能项目只是上次显示的一部分。
我想恢复完全相同的位置。
我尝试了以下一些方法,但没有一种是完美的。
有人可以帮忙吗?
1.第一种方式。
我使用onScrolled计算滚动的确切位置,当滚动停止时,保存位置。当 spinner 更改数据集 或 fragment onCreat 时,恢复所选数据集的位置。一些数据集可能有很多很多行。
app被销毁后可以保存恢复,但可能计算量太大?
会导致
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.
如果scrollY很大,比如111111,当打开fragment时,RecyclerView会先显示列表从第一个item开始,延迟一段时间后,滚动到scrollY位置。
如何做到不耽误?
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.第二种方式。
这可以完美运行,但它只能在片段生命周期中工作。
我尝试使用ObjectOutputStream和ObjectInputStream来保存和恢复HashMap,但是不起作用。
如何保存在内存中?
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.第三条路。
我改了第二种方式,使用Bundle而不是HashMap,但是也有同样的问题,退出fragment生命周期就不行了。
我使用manually serialize/deserialize android bundle将bundle保存在内存中,但是在恢复时,它没有得到有效的bundle。
================================================ ========================= 解决方案
谢谢大家!
我终于解决了这个问题,你可以在my code看到,只要看到这2个方法:saveRecyclerViewPosition和restoreWordRecyclerViewPosition。
【问题讨论】:
-
可能只是从布局管理器获取第一个显示的项目ID及其偏移量,然后您可以移动到重新创建的位置并通过偏移量调整滚动。如果您的数据集在此期间发生更改,这也可能会起作用。
-
@bleeding182 谢谢。我也有这种想法,但我不知道如何获得项目的偏移量?每个项目都有不同的高度
-
你可以从 layoutmanager 中获取视图,然后读取 getTop() 或 getDecoratedTop(),这与 recyclerview.top 之间的差异将是你的偏移量;)即使你没有得到向右偏移,您至少会在正确的位置而不跳帧
-
当我在
onScrollStateChanged中使用lastCompletelyPosition = ((LinearLayoutManager)recyclerView.getLayoutManager()).findLastCompletelyVisibleItemPosition();lastCompleteChild = recyclerView.getChildAt(lastCompletelyPosition);时无法获取项目视图,lastCompleteChild.getTop()将抛出InvocationTargetException
标签: android listview android-recyclerview