Fragment中使用RecyclerView报错:No adapter attached skipping layout
解决RecyclerView在Fragment中不显示且报错"No adapter attached; skipping layout"的问题
我仔细看了你的代码和问题描述,虽然你已经排查了常见的Adapter初始化时机问题,但还有几个关键的细节错误导致了当前的问题,我帮你逐一梳理并给出修复方案:
问题1:DataBinding的错误使用
你在onCreateView里同时做了两件矛盾的事:用inflater.inflate加载布局,又调用DataBindingUtil.setContentView给Activity绑定布局——这完全是错误的用法!
DataBindingUtil.setContentView是给Activity初始化DataBinding用的,Fragment里必须用DataBindingUtil.inflate来加载布局,而且你返回的view和绑定的view不是同一个实例,导致后续onViewCreated里拿到的RecyclerView根本不是布局文件中定义的那个。
问题2:列表引用被替换,Adapter持有的还是旧空列表
在prepareWeightData方法里,你直接把mWeightData重新赋值为数据库查询的新List:
mWeightData = SQLite.select(). from(WeightData.class).queryList();
但你的Adapter在初始化时已经持有了原来空ArrayList的引用,新的List对象和Adapter里的mList没有任何关联,所以调用notifyDataSetChanged()根本不会生效——Adapter里的列表还是空的!
问题3:ListAdapter的getItemCount方法未完成
你的ListAdapter代码里,getItemCount()方法没有返回值,RecyclerView无法知道列表有多少项,自然不会渲染任何内容。
修复后的完整代码
1. 修正HistoryFragment代码
import android.databinding.DataBindingUtil; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.example.gosia.weightapplication.databinding.FragmentHistoryBinding; import com.example.gosia.weightapplication.model.WeightData; import com.orhanobut.logger.Logger; import com.raizlabs.android.dbflow.sql.language.SQLite; import java.util.ArrayList; import java.util.List; public class HistoryFragment extends Fragment { private List<WeightData> mWeightData = new ArrayList<>(); private FragmentHistoryBinding mFragmentHistoryBinding; private ListAdapter mAdapter; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup viewGroup, Bundle savedInstanceState) { // 修正Fragment的DataBinding初始化方式 mFragmentHistoryBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_history, viewGroup, false); mFragmentHistoryBinding.setVariable(this); // 返回绑定的根View return mFragmentHistoryBinding.getRoot(); } @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); // 直接从Binding对象获取RecyclerView,无需findViewById RecyclerView recyclerView = mFragmentHistoryBinding.recyclerView; RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getContext()); recyclerView.setLayoutManager(layoutManager); // 初始化Adapter mAdapter = new ListAdapter(mWeightData, getContext()); recyclerView.setAdapter(mAdapter); prepareWeightData(); } private void prepareWeightData() { List<WeightData> newData = SQLite.select().from(WeightData.class).queryList(); Logger.d(newData.toString()); // 不要替换整个列表,清空旧数据后添加新数据,保持引用一致 mWeightData.clear(); mWeightData.addAll(newData); // 通知Adapter数据更新 mAdapter.notifyDataSetChanged(); } }
2. 修正ListAdapter的getItemCount方法
import android.content.Context; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import com.example.gosia.weightapplication.model.WeightData; import java.util.List; public class ListAdapter extends RecyclerView.Adapter<ListAdapter.ViewHolder> { private List<WeightData> mList; private Context mContext; private final LayoutInflater mLayoutInflater; public static class ViewHolder extends RecyclerView.ViewHolder { public TextView date, weight; public ImageView image; public ViewHolder(View v) { super(v); date = v.findViewById(R.id.text_view_date); weight = v.findViewById(R.id.text_view_weight); image = v.findViewById(R.id.image); } } public ListAdapter(List<WeightData> plist, Context pContext) { this.mList = plist; this.mContext = pContext; this.mLayoutInflater = LayoutInflater.from(this.mContext); } @Override public ListAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View v = this.mLayoutInflater.inflate(R.layout.item_weight_history, parent, false); ViewHolder vh = new ViewHolder(v); return vh; } @Override public void onBindViewHolder(ViewHolder holder, int position) { //set data WeightData weightData = mList.get(position); holder.date.setText(weightData.getLastDayWeightMeasurement()); holder.weight.setText(weightData.getWeight()); } // 补全getItemCount方法,返回列表实际长度 @Override public int getItemCount() { return mList != null ? mList.size() : 0; } }
额外提示
- 以后在Fragment中使用DataBinding时,务必用
DataBindingUtil.inflate初始化,并且返回getRoot()作为Fragment的View; - 更新列表数据时,尽量不要直接替换List对象,而是通过
clear()+addAll()的方式保持引用一致,这样Adapter才能感知到数据变化; - 一定要确保Adapter的
getItemCount()正确返回列表长度,否则RecyclerView无法渲染列表项。
内容的提问来源于stack exchange,提问作者Pefredo
相关产品推荐
相关产品推荐

