问题
I'm trying to use RecyclerView in Fragment, but I'm facing a problem, my list doesn't appear and I have this error:
E/RecyclerView: No adapter attached; skipping layout
I checked the solutions, apparently the problems appeared when:
RecyclerView initialized after Adapter
Bind and set recyclerView in onCreateView instead of onViewCreated
But I gave attention, I tried alternatives and I'm still facing the same issue.
Here is my code of the fragment:
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) {
View view = inflater.inflate(R.layout.fragment_history, viewGroup, false);
//binding variable
mFragmentHistoryBinding = DataBindingUtil.setContentView(getActivity(), R.layout.fragment_history);
mFragmentHistoryBinding.setVariable(this);
return view;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
//recycler
RecyclerView recyclerView = view.findViewById(R.id.recycler_view);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getContext());
recyclerView.setLayoutManager(layoutManager);
// define an adapter
mAdapter = new ListAdapter(mWeightData, getContext());
recyclerView.setAdapter(mAdapter);
prepareWeightData();
}
private void prepareWeightData() {
mWeightData = SQLite.select().
from(WeightData.class).queryList();
Logger.d(mWeightData.toString()); //The list isn't null, I have data to show
mAdapter.notifyDataSetChanged();
}
}
The XML:
<?xml version="1.0" encoding="utf-8"?>
<layout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<import type="android.view.View" />
<variable
name="variable"
type="com.example.gosia.weightapplication.HistoryFragment" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorWhite"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorBlack">
</View>
</LinearLayout>
</layout>
Code of the ListAdapter:
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());
}
@Override
public int getItemCount() {
return mList.size();
}
}
And my Activity is properly extending android.support.v7.app.AppCompatActivity
Any help would be appreciated
Edit: it's apparently related to this DataBindingUtil?
回答1:
I run your code without bindings and its working perfect. You should check your bindings
public class HistoryFragment extends Fragment {
private ListAdapter mAdapter;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup viewGroup, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_history, viewGroup, false);
return view;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
//recycler
RecyclerView recyclerView = view.findViewById(R.id.recycler_view);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getContext());
recyclerView.setLayoutManager(layoutManager);
// define an adapter
mAdapter = new ListAdapter(null, getContext());
recyclerView.setAdapter(mAdapter);
}
}
even with getContext() it will work and if you are passing null list though it will just not show anything on recycler view but will not give skipping layout error.
回答2:
Pass the correct context to the adapter class
Change this
getContext()
to
getActivity()
It should look like this
mAdapter = new ListAdapter(mWeightData, getActivity(());
recyclerView.setAdapter(mAdapter);
Also
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getActivity());
and always pass use getActivity() in fragment:- more info here
Using context in a fragment
回答3:
make some changes like this way if you getting data then show it..
recyclerView.setLayoutManager(new LinearLayoutManager(this));
private void prepareWeightData() {
mWeightData = SQLite.select().
from(WeightData.class).queryList();
Logger.d(mWeightData.toString()); //The list isn't null, I have data to show
mAdapter = new ListAdapter(mWeightData, getContext());
recyclerView.setAdapter(mAdapter);
mAdapter.notifyDataSetChanged();
}
make some changes in adapter ..
public class ListAdapter extends RecyclerView.Adapter<ListAdapter.ViewHolder> {
private List<WeightData> mList;
private Context mContext;
public 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;
}
@Override
public ListAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_weight_history, parent, false);
return new ViewHolder(v);
}
@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());
}
@Override
public int getItemCount() {
return mList.size();
}
}
回答4:
Merging onCreateView and onViewCreated (see below) works for me (the error disappears)
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup viewGroup, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_first, viewGroup, false);
//binding variable
mFragmentHistoryBinding = DataBindingUtil.setContentView(getActivity(), R.layout.fragment_first);
mFragmentHistoryBinding.setVariable(this);
//recycler
RecyclerView recyclerView = view.findViewById(R.id.recycler_view);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getContext());
recyclerView.setLayoutManager(layoutManager);
// define an adapter
mAdapter = new ListAdapter(mWeightData, getContext());
recyclerView.setAdapter(mAdapter);
prepareWeightData();
return view;
}
EDIT
Change your adapter like this:
public class ListAdapter extends RecyclerView.Adapter<ListAdapter.ViewHolder> {
private final List<WeightData> mList;
//... existing code
public void updateDataSet(List<WeightData> weightData) {
mList.clear();
mList.addAll(weightData);
notifyDataSetChanged();
}
public ListAdapter(Context pContext) {
this.mList = new ArrayList<>();
this.mContext = pContext;
this.mLayoutInflater = LayoutInflater.from(this.mContext);
}
//... existing code
}
in onCreateView (updated from below)
// define an adapter
mAdapter = new ListAdapter(getContext());
recyclerView.setAdapter(mAdapter);
prepareWeightData();
return view;
}
prepareWeightData method:
private void prepareWeightData() {
List<WeightData> weightData = SQLite.select().
from(WeightData.class).queryList();
Logger.d(weightData.toString()); //The list isn't null, I have data to show
mAdapter.updateDataSet(weightData);
}
来源:https://stackoverflow.com/questions/50273294/recyclerview-in-fragment-no-adapter-attached-skipping-layout