当前位置: 首页 > 知识库问答 >
问题:

如何保存和恢复RecyclerView的滚动确切位置?[重复]

邵飞白
2023-03-14

抱歉,我的英语很差。

我想要确切的位置。并且在活动/片段被销毁后(不管是我销毁它还是系统销毁它),我重新打开活动/片段,< code > recycle view 也可以在它被销毁的相同位置。

“相同”并不意味着“项目位置”,因为项目可能只是上次显示的一部分。

我想恢复完全相同的位置。

我尝试了下面的一些方法,但没有人是完美的。

有人可以帮忙吗?

1.First方式。

我使用< code>onScrolled来计算滚动的精确位置,当滚动停止时,保存位置。当spinner在onCreat上更改数据集或片段时,恢复所选数据集的位置。一些数据集可能有许多行。

它可以在应用程序被销毁后保存和恢复,但可能会有太多计算?

它会导致

跳过了 60 帧!应用程序可能在其主线程上执行了太多工作。尝试完成输入事件,但输入事件接收器已被释放。android total arena pages for jit.

如果< code>scrollY很大,像< code>111111,当打开片段时,RecyclerView将首先显示从第一项开始的列表,经过一段延迟后,它将滚动到< code>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.第二种方式。

这运行起来很完美,但是它只能在片段生命周期中工作。

我尝试使用ObjectOutputStreamObjectInputStream来保存和恢复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.Third方式。

我改变了第二种方法,使用<code>Bundle,但它有同样的问题,在片段生命周期之外不起作用。

我使用手动序列化/反序列化android bundle将bundle保存在内存中,但在恢复它时,它没有获得有效的bundle

======================================================================= 解决方案

谢谢大家!

最后我解决了这个问题,你可以在我的代码中看到它,只需看到这2个方法:saveRecyclerViewPosition和restoreWordRecyclerViewPosition。

共有1个答案

壤驷康裕
2023-03-14

所以现在我有时间浪费;)以下是完整的答案:

基本布局。是的,它可以被优化。这不是重点;)

<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>

您要做的是获取第一个可见项及其位置。如果您有固定的id,您可以添加逻辑以在适配器中查找id/位置。

一些基本适配器:

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;
    }
}

您可以随意保存它的状态,我使用了SharedReferences,并在开始时再次阅读。我延迟了滚动,因为如果滚动到紧跟其后的位置,则滚动不起作用。这只是一个基本的例子,如果你多和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();
    }
}

这将做什么,它将再次显示正确的项目,并在这500毫秒后跳回正确的位置,它被保存。

一定要添加空检查和排序

希望这有帮助!

 类似资料:
  • 我有一个从Firebase数据库检索数据的简单片段。我使用firebase recycler视图显示检索数据。在滚动或屏幕旋转后,我无法强制回收器视图(或线性布局管理器)恢复滚动位置。 我在这里找到了一些答案,但它们不起作用。 我的代码是: 公共类NewsListFragment扩展了ParentNewsFragment{ } 最后的showToast方法显示了位置的真实数量,但recyclerv

  • 我制作了一个recyclerview网格,一旦用户按下按钮,它就会被api中的数据填满。旋转屏幕后,滚动位置会短暂恢复,然后再向上滚动到网格顶部。我使用本教程来保留我的滚动位置: 我还在本教程中尝试保存布局状态。 我的舱单条目是:

  • 是否有一种方法可以在完成刷取并对实例调用之后恢复刷取操作并将视图保持器还原到其初始位置?我使用了、和实例来完美地协同工作,在某些情况下,我只需要恢复swipe操作,而不删除被刷过的项。

  • 我正在使用盖茨比2.2.10设置一个网站,链接组件保留了上一页的滚动位置,并且在点击时没有滚动回顶部。 预期行为: 当您单击“隐私政策”、“第2页”或网站底部的任何页面时,我希望页面加载时用户返回顶部。 实际行为: 用户停留在当前页面的滚动位置

  • 如何刷新显示在中的数据(在其适配器上调用),并确保滚动位置被重置到它原来的位置? 如果是良好的ol'则只需检索,检查其,然后使用相同的精确数据调用。 在的情况下,这似乎是不可能的。 我想我应该使用它的,它确实提供了,但是检索位置和偏移量的正确方法是什么? 和? 还是有更优雅的方法来完成这项工作?

  • 在TensorFlow中训练模型后: 如何保存已训练的模型? 以后如何还原此保存的模型?