You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

RecyclerView滚动导致数据丢失、焦点失效问题求助

解决RecyclerView滚动后数据丢失+焦点丢失问题

这个问题其实是RecyclerView的视图复用机制搞的鬼,我来给你拆解下原因和解决方案:

一、数据丢失的核心原因

你点击按钮修改了item的显示内容,但只是改了当前View的状态,并没有同步更新背后的数据源列表。当item滚出屏幕被回收,再次滚回来时,RecyclerView会重新调用onBindViewHolder,这时候它会从原始数据源里取数据绑定,自然就恢复成原来的样子了。

解决方案:修改UI的同时同步更新数据源

  1. 首先,确保你的Adapter持有一个可变的数据源列表(比如ArrayList<YourDataModel>),而不是每次都用新列表。
  2. 在按钮点击事件里,先修改数据源中对应position的对象属性,再通知Adapter更新这个item:
// 假设你的Adapter里的按钮点击逻辑
holder.adapterBtn.setOnClickListener(v -> {
    // 1. 获取当前position对应的数据源对象
    YourDataModel item = mDataList.get(holder.getAdapterPosition());
    // 2. 修改对象的属性(比如把状态改成"已修改")
    item.setStatus("已修改");
    // 3. 通知Adapter更新这个item(用notifyItemChanged比notifyDataSetChanged更高效)
    notifyItemChanged(holder.getAdapterPosition());
});
  1. 如果你需要在Activity里做后续处理(比如保存到本地),可以给Adapter设置一个回调接口,把修改后的数据传回去。

二、焦点丢失的处理方案

滚动时焦点丢失也是因为视图复用,被回收的item焦点状态没有被保存,重新绑定的时候没恢复。这里分两种情况处理:

情况1:普通控件(比如TextView/Button)的焦点

  • 给每个数据模型加一个字段,用来记录该item的焦点状态(比如boolean isFocused)。
  • 在onBindViewHolder里,根据数据源的状态恢复焦点:
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
    YourDataModel item = mDataList.get(position);
    // 恢复焦点状态
    if (item.isFocused()) {
        holder.targetView.requestFocus();
    } else {
        holder.targetView.clearFocus();
    }
}
  • 在onViewRecycled里,保存当前item的焦点状态到数据源:
@Override
public void onViewRecycled(ViewHolder holder) {
    super.onViewRecycled(holder);
    int position = holder.getAdapterPosition();
    if (position != RecyclerView.NO_POSITION) {
        YourDataModel item = mDataList.get(position);
        item.setFocused(holder.targetView.hasFocus());
    }
}

情况2:EditText这类输入控件的焦点+内容

除了保存焦点状态,还要保存输入的内容,不然滚动回来输入的文字也会丢:

// onBindViewHolder里恢复内容和焦点
holder.editText.setText(item.getInputText());
if (item.isFocused()) {
    holder.editText.requestFocus();
    // 还可以把光标定位到最后
    holder.editText.setSelection(holder.editText.getText().length());
}

// onViewRecycled里保存内容和焦点
@Override
public void onViewRecycled(ViewHolder holder) {
    super.onViewRecycled(holder);
    int position = holder.getAdapterPosition();
    if (position != RecyclerView.NO_POSITION) {
        YourDataModel item = mDataList.get(position);
        item.setInputText(holder.editText.getText().toString());
        item.setFocused(holder.editText.hasFocus());
    }
}

额外优化:开启稳定ID

给Adapter设置setHasStableIds(true),并重写getItemId返回每个item的唯一标识(比如数据模型里的id字段),这样RecyclerView能更准确地复用视图,减少不必要的状态丢失:

public class YourAdapter extends RecyclerView.Adapter<YourAdapter.ViewHolder> {
    public YourAdapter(List<YourDataModel> dataList) {
        mDataList = dataList;
        setHasStableIds(true);
    }

    @Override
    public long getItemId(int position) {
        // 返回item的唯一ID,比如数据里的id
        return mDataList.get(position).getId();
    }
}

三、结合你的代码场景补充

在你的fetchNotification方法里,拿到接口返回的数据后,要把数据存入一个全局的可变列表,然后初始化Adapter时传入这个列表。后续所有修改都要操作这个列表,而不是临时创建新列表。

比如:

// Activity里定义全局数据源
private List<YourDataModel> mNotificationList = new ArrayList<>();
private YourAdapter mAdapter;

public void fetchNotification() {
    String url = "https://www.videobeaker.com/secure/assests/video-beaker-api/get-data.php?getPodiums=1";
    StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
            response -> {
                // 解析接口数据到全局列表
                mNotificationList.clear();
                mNotificationList.addAll(parseResponseToModelList(response));
                // 初始化或更新Adapter
                if (mAdapter == null) {
                    mAdapter = new YourAdapter(mNotificationList);
                    mRecyclerView.setAdapter(mAdapter);
                } else {
                    mAdapter.notifyDataSetChanged();
                }
            },
            error -> {
                // 处理请求错误
            });
    Volley.newRequestQueue(this).add(stringRequest);
}

这样操作下来,滚动后数据就不会丢失,焦点状态也能正常保留啦~

内容的提问来源于stack exchange,提问作者Harish Rawal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 08:27:58