You need to enable JavaScript to run this app. Android:调用notifyDataSetChanged()后RecyclerView需点击EditText才更新
优惠活动
大模型
产品
解决方案
定价
更多

Android:调用notifyDataSetChanged()后RecyclerView需点击EditText才更新

问题根因
  • 出现该现象的核心原因是 在子线程中直接调用RecyclerView Adapter的notifyDataSetChanged()方法
  • Android存在严格的UI操作线程约束:所有和视图绘制、布局更新相关的触发逻辑,必须在主线程(UI线程)执行才会被立即调度。与原生View的setText、setVisibility等方法自带线程检查不同,RecyclerView的Adapter的notify类方法没有强制校验调用线程,在子线程发起的数据集变更通知不会被立即触发重绘流程,只会等待下一次主线程处理到布局绘制任务时才生效
  • 你的代码中将SOAP网络请求、数据解析逻辑全部放在独立的SOAPCONNECT Runnable(子线程)中执行,子线程内调用listSPAdapter.notifyDataSetChanged()时,不会立即触发RecyclerView的重绘调度;当你触碰EditText时,输入框的焦点变化、触摸反馈触发了一次主线程的布局重绘流程,才顺带读取到最新的数据集完成刷新,也就出现了“发起请求后不立即更新,点一下输入框才显示数据”的现象。
修复方案

1. 将数据集更新、Adapter刷新逻辑切回主线程执行

在SOAP请求完成、数据解析结束后,必须把刷新操作投递到主线程执行,确保notify方法触发的重绘请求能被立即调度。可以通过以下两种常用方式实现:

  • 调用当前Activity的runOnUiThread()方法,把更新逻辑包裹在主线程Runnable中
  • 通过绑定主线程的Handler发送空消息,在消息处理回调中执行更新

注意:不要在子线程内直接操作Adapter实例或调用任何与视图更新相关的方法

2. 修复现有逻辑的已知隐患

  • 每次发起新请求前,先调用arrSanPham.clear()清空旧数据集,避免多次请求时新旧数据重复叠加
  • 优化异常处理逻辑,请求失败、数据解析出错时给用户明确的界面提示,不要只打印后台日志
核心代码修改示例

原错误的子线程内更新写法:

// 运行在子线程的run()方法内
for (int i = 0;i<tongSP;i++){
    // ... 数据解析逻辑
    arrSanPham.add(new SanPham(...));
}
listSPAdapter.notifyDataSetChanged();

修改后的正确实现:

@Override
public void run() {
    // 原有SOAP请求、网络交互的子线程逻辑保持不变
    try{
        ht.call(SOAP_ACTION,envelope);
        // ... 原有SOAP数据解析逻辑
        int tongSP = Sanpham.getPropertyCount();
        // 把UI更新逻辑投递到主线程执行
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                // 先清空旧数据,避免重复叠加
                arrSanPham.clear();
                // 解析并添加本次的新数据
                for (int i = 0;i<tongSP;i++){
                    SoapObject Sanpham1 = (SoapObject) Sanpham.getProperty(i);
                    arrSanPham.add(new SanPham(
                            Integer.parseInt(Sanpham1.getProperty("MaSanPham").toString()),
                            Integer.parseInt(Sanpham1.getProperty("SoLuong").toString()),
                            Sanpham1.getProperty("TenSanPham").toString()
                    ));
                }
                // 主线程内调用刷新,会立即触发重绘
                listSPAdapter.notifyDataSetChanged();
            }
        });
    }catch(Exception e){
        Log.d("Error","Error while recieving data");
        // 失败提示也需要切到主线程显示
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(YourActivity.this, "请求失败,请稍后重试", Toast.LENGTH_SHORT).show();
            }
        });
    }
}
长期优化建议
  • 将SOAPCONNECT改为静态内部类,避免隐式持有外部Activity引用造成内存泄漏
  • 网络请求过程中增加全局/局部加载提示,避免用户重复点击发起无效请求
  • 替换全量刷新的notifyDataSetChanged()方法,改用notifyItemRangeInserted()做定向刷新,减少列表的整体重绘开销,提升滑动流畅度

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.10 17:45:05