Daw*_*nYu 6 android listview android-recyclerview
抱歉我的英语不好.
我想要确切的位置.在活动/片段被破坏之后(无论我是破坏它还是系统破坏它),我重新打开活动/片段,它RecyclerView也可以作为被破坏的相同位置.
该"相同"不是指"项目位置",因为也许只是项显示部分最后一次.
我希望恢复完全相同的位置.
我在下面尝试了一些方法,但没有人是完美的.
有人可以帮忙吗?
1.第一种方式.
我onScrolled用来计算滚动的确切位置,当滚动停止时,保存位置.当微调器更改数据集或片段onCreat时,恢复所选数据集的位置.某些数据集可能有许多行.
它可以在应用程序被销毁后保存和恢复,但可能有太多的计算?
它会导致
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,当打开片段时,RecyclerView将首先显示从第一个项目开始的列表,并在一段延迟后,它滚动到该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) {
}
});
Run Code Online (Sandbox Code Playgroud)
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;
}
Run Code Online (Sandbox Code Playgroud)
3.第三种方式.
我改变第二种方式,使用Bundle而不是HashMap,但它有相同的问题,在片段生命周期之外不起作用.
我使用手动序列化/反序列化android包来保存bundle在内存中,但是当恢复它时,它不会获得有效bundle.
================================================== ===================== 解决方案
感谢大家!
最后我解决了这个问题,你可以在我的代码中看到它,只看到这两个方法:saveRecyclerViewPosition和restoreWordRecyclerViewPosition.
所以现在我有时间浪费;)这是一个完整的答案:
基本布局.是的,它可以优化.那不是重点;)
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity">
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
Run Code Online (Sandbox Code Playgroud)
你想要做的是获得第一个可见项目及其位置.如果你有固定的id,你可以添加逻辑来在id中查找适配器中的id/position.
一些基本适配器:
public class TestAdapter extends RecyclerView.Adapter {
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new RecyclerView.ViewHolder(LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_list_item_1, parent, false)) {
};
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
((TextView) holder.itemView).setText("Position " + position);
}
@Override
public int getItemCount() {
return 30;
}
}
Run Code Online (Sandbox Code Playgroud)
你喜欢它保存它的状态,我使用SharedPreferences,并在开始时再次阅读它.我postDelayed滚动,因为它滚动到位置后立即跟随它不起作用.这只是一个基本的例子,如果你更多地使用LayoutManager,可能有更好的方法.
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.View;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private RecyclerView recyclerView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = (RecyclerView) findViewById(R.id.recycler);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(new TestAdapter());
}
@Override
protected void onResume() {
super.onResume();
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
recyclerView.scrollToPosition(preferences.getInt("position", 0));
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
recyclerView.scrollBy(0, - preferences.getInt("offset", 0));
}
}, 500);
}
@Override
protected void onPause() {
super.onPause();
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
View firstChild = recyclerView.getChildAt(0);
int firstVisiblePosition = recyclerView.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();
}
}
Run Code Online (Sandbox Code Playgroud)
这将做什么,它将再次显示正确的项目,并在那500毫秒跳回到正确的位置后,它被保存.
一定要添加空检查和排序!
希望这可以帮助!
| 归档时间: |
|
| 查看次数: |
6997 次 |
| 最近记录: |