RecyclerView.Adapter未调用onCreateViewHolder/onBindViewHolder问题排查
RecyclerView 数据不显示问题排查方案
核心问题定位
你遇到的矛盾点(Adapter已绑定却仍报“No adapter attached; skipping layout”、数据加载完成但ViewHolder方法不执行),通常是Adapter绑定时机、数据有效性、RecyclerView初始化流程这几个环节出了问题,以下是针对性排查方案:
1. 先确认Cursor是否真的有数据
- 调用
cursor.getCount()直接打印数据量,如果返回0,Adapter自然不会创建任何ViewHolder。要检查数据库查询语句是否正确、数据是否真的写入到了对应表中。 - 若使用Cursor相关Adapter,确保Cursor已执行
moveToFirst()(部分实现依赖此操作来识别有效数据)。
2. 修正Adapter绑定时机
“No adapter attached; skipping layout”本质是RecyclerView第一次布局时,Adapter还未被设置。解决思路是先绑定空Adapter,再更新数据:
// 在Activity/Fragment初始化阶段(比如onCreate/onViewCreated)先绑定空Adapter DurationsRVAdapter adapter = new DurationsRVAdapter(null); recyclerView.setLayoutManager(new LinearLayoutManager(this)); // 必须先设LayoutManager recyclerView.setAdapter(adapter); // 异步加载数据完成后,更新Cursor并通知Adapter adapter.swapCursor(loadedCursor); adapter.notifyDataSetChanged();
3. 检查RecyclerView的基础配置
- 必须设置LayoutManager:没有LayoutManager的RecyclerView无法布局子项,这是高频遗漏点。
- 布局参数有效性:如果RecyclerView嵌套在ScrollView中,需添加
android:nestedScrollingEnabled="false",同时确保RecyclerView的layout_height不是wrap_content(旧版本RecyclerView对wrap_content支持有问题,建议用match_parent或固定高度)。
4. 验证Adapter的核心方法实现
确保DurationsRVAdapter的以下方法逻辑正确:
// 重写getItemCount,确保返回Cursor实际数据量 @Override public int getItemCount() { return mCursor != null ? mCursor.getCount() : 0; } // 若自定义了swapCursor方法,需正确处理Cursor切换 public void swapCursor(Cursor newCursor) { Cursor oldCursor = mCursor; mCursor = newCursor; if (oldCursor != null) { oldCursor.close(); // 避免内存泄漏 } notifyDataSetChanged(); // 数据更新后必须通知 }
5. 确认notifyDataSetChanged()的调用线程
必须在主线程调用notifyDataSetChanged(),如果是在数据库查询的后台线程中更新数据,要切换到主线程执行:
runOnUiThread(() -> { mAdapter.notifyDataSetChanged(); });
代码检查重点
- DurationsReport(页面类):检查RecyclerView初始化顺序是否是「设置LayoutManager → 设置Adapter → 加载数据」,避免数据加载完成后才绑定Adapter。
- DurationsRVAdapter:检查
onCreateViewHolder的布局加载是否正确、onBindViewHolder中是否正确从Cursor读取数据。 - 布局文件:确认RecyclerView的父布局没有将其挤压为0高度,比如避免在ConstraintLayout中未设置正确的约束条件。
内容的提问来源于stack exchange,提问作者Ben Edwards
相关产品推荐
相关产品推荐

