RecyclerView加载更多失效:无ProgressBar/数据,Logcat警告修复求助
修复RecyclerView滚动加载时ProgressBar不显示且无数据加载的问题
这个问题的根源就是Logcat里的警告明确提示的——你在RecyclerView的滚动回调(比如OnScrollListener的onScrolled方法)里直接执行了修改Adapter数据的操作,而滚动回调可能在RecyclerView的measure/layout阶段运行,这时候修改数据会触发框架的限制,导致你的加载逻辑没正常执行,ProgressBar也无法显示。
核心修复步骤
1. 把所有数据修改操作延迟到主线程下一个消息帧
你当前的loadMore()方法开头就直接修改列表并通知Adapter更新,这部分是在滚动回调的同步流程里执行的,正是触发警告的原因。要把整个数据修改逻辑都放到Handler.post()或者View.post()里,避开measure/layout阶段。
修改后的loadMore()代码:
private void loadMore() { // 先判断是否正在加载,避免重复触发 if (isLoading) return; isLoading = true; // 把所有操作放到主线程下一个消息帧执行,避开滚动回调的布局阶段 new Handler(Looper.getMainLooper()).post(() -> { // 添加加载占位项(null),显示ProgressBar arraylist.add(null); mListadapter.notifyItemInserted(arraylist.size() - 1); // 模拟加载延迟(实际场景替换成网络请求/本地数据加载) new Handler(Looper.getMainLooper()).postDelayed(() -> { // 移除占位项 arraylist.remove(arraylist.size() - 1); int scrollPosition = arraylist.size(); mListadapter.notifyItemRemoved(scrollPosition); int currentSize = scrollPosition; int nextLimit = currentSize + 5; Log.e("currentSize", "" + currentSize); Log.e("nextLimit", "" + nextLimit); // 加载新数据(修复索引越界问题) int endIndex = Math.min(nextLimit, DataNoteImformation.id.length); while (currentSize < endIndex) { DataNote wp2 = new DataNote( DataNoteImformation.id[currentSize], DataNoteImformation.branchArray[currentSize], DataNoteImformation.assetcodeArray[currentSize], DataNoteImformation.customerArray[currentSize], DataNoteImformation.licenseplateArray[currentSize] ); arraylist.add(wp2); currentSize++; } // 高效通知Adapter数据更新(比notifyDataSetChanged性能更好) mListadapter.notifyItemRangeInserted(scrollPosition, currentSize - scrollPosition); isLoading = false; }, 2000); }); }
2. 确保Adapter正确处理加载占位项
你的Adapter需要区分普通数据项和加载项的ViewType,这样才能正常显示ProgressBar:
// 在Adapter里定义两个ViewType常量 private static final int VIEW_TYPE_ITEM = 0; private static final int VIEW_TYPE_LOADING = 1; @Override public int getItemViewType(int position) { // 判断当前项是否是加载占位项(null) return arraylist.get(position) == null ? VIEW_TYPE_LOADING : VIEW_TYPE_ITEM; } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (viewType == VIEW_TYPE_ITEM) { // 创建普通数据项的ViewHolder(你的原有逻辑) View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.your_item_layout, parent, false); return new YourItemViewHolder(view); } else { // 创建加载项的ViewHolder(显示ProgressBar) View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_loading, parent, false); return new LoadingViewHolder(view); } } // 加载项的ViewHolder static class LoadingViewHolder extends RecyclerView.ViewHolder { ProgressBar progressBar; public LoadingViewHolder(View itemView) { super(itemView); progressBar = itemView.findViewById(R.id.progress_bar); } }
3. 修复滚动回调里的调用逻辑
如果你之前是在OnScrollListener的onScrolled里直接调用loadMore(),现在要确保调用时机正确,并且加上isLoading的判断:
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager(); // 判断是否滚动到底部,且不在加载中 if (!isLoading && layoutManager != null && layoutManager.findLastCompletelyVisibleItemPosition() == arraylist.size() - 1) { // 延迟调用loadMore,确保不在布局阶段执行 recyclerView.post(() -> loadMore()); } } });
额外优化点
- 替换
notifyDataSetChanged()为notifyItemRangeInserted(),避免RecyclerView重新渲染所有项,提升性能 - 修复了原代码中数组索引越界的问题(原
currentSize + 1 <= nextLimit会导致访问到数组长度的索引,数组索引从0开始,改成currentSize < endIndex更安全) - 给
Handler指定主线程的Looper,避免在非主线程创建Handler导致的异常
内容的提问来源于stack exchange,提问作者D3D
相关产品推荐
相关产品推荐

