Xin lỗi vì tiếng Anh nghèo nàn của tôi.Làm cách nào để lưu và khôi phục vị trí chính xác của cuộn RecyclerView?
Tôi muốn vị trí chính xác. Và sau khi hoạt động/mảnh đã phá hủy (dù tôi tiêu diệt nó hoặc hệ thống phá hủy nó), tôi mở lại hoạt động/mảnh, các RecyclerView
thể cũng như các vị trí tương đương vì nó bị phá hủy.
"cùng" không có nghĩa là "vị trí mục", vì có thể mục chỉ hiển thị một phần thời gian qua.
Tôi muốn khôi phục chính xác cùng một vị trí.
Tôi đã thử một số cách dưới đây, nhưng không ai hoàn hảo.
Ai đó có thể trợ giúp?
1.Đầu tiên.
Tôi sử dụng onScrolled
để tính toán vị trí chính xác của cuộn, khi di chuyển dừng, lưu vị trí. Khi spinner thay đổi tập dữ liệu hoặc fragment onCreat, khôi phục vị trí của tập dữ liệu đã chọn. Một số bộ dữ liệu có thể có nhiều hàng.
Nó có thể lưu và khôi phục sau khi ứng dụng bị phá hủy, nhưng có thể có quá nhiều calculte?
Nó sẽ gây ra
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.
Và nếu scrollY
là rất lớn, giống như 111111
, khi mở đoạn, đầu tiên RecyclerView sẽ hiển thị danh sách bắt đầu từ mục đầu tiên, và sau khi một số chậm trễ, nó cuộn đến vị trí scrollY
.
Làm thế nào để làm cho nó không chậm trễ?
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 cách.
Điều này chạy hoàn hảo, nhưng nó chỉ có thể hoạt động trong vòng đời phân đoạn.
Tôi cố gắng sử dụng ObjectOutputStream
và ObjectInputStream
để lưu và khôi phục HashMap
nhưng không hoạt động.
Cách lưu bộ nhớ trong bộ nhớ?
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 cách.
tôi thay đổi cách thứ hai, sử dụng Bundle
thay vì HashMap
, nhưng nó có cùng một câu hỏi, không hoạt động khi ra khỏi vòng đời mảnh.
Tôi sử dụng manually serialize/deserialize android bundle để lưu bundle
trong bộ nhớ, nhưng khi khôi phục, nó không nhận được bundle
hợp lệ.
============================================== ========================= giải pháp
Cảm ơn tất cả mọi người!
Cuối cùng tôi giải quyết vấn đề này, bạn có thể nhìn thấy nó trong my code, chỉ cần nhìn thấy những 2 phương pháp: saveRecyclerViewPosition và restoreWordRecyclerViewPosition.
có thể chỉ nhận được id mục được hiển thị đầu tiên và giá trị bù trừ của nó từ trình bố cục, sau đó bạn có thể di chuyển đến vị trí khi tạo lại và điều chỉnh cuộn theo độ lệch. điều này có thể cũng sẽ hoạt động nếu tập dữ liệu của bạn thay đổi trong thời gian chờ đợi. –
@ bleeding182 thanks.I cũng đã nghĩ theo cách này, nhưng tôi không biết làm thế nào để có được bù đắp của một mục? mỗi mục có chiều cao khác nhau – DawnYu
bạn chỉ có thể xem được từ layoutmanager, sau đó đọc getTop() hoặc getDecoratedTop(), sự khác biệt giữa điều đó và recyclerview.top sẽ là bù đắp của bạn;) Và ngay cả khi bạn không nhận được bù đắp phải, bạn sẽ có ít nhất vào đúng vị trí mà không bỏ qua các khung hình –