Reputation: 57
I am using a Fragment to view a RecyclerView. But I always get this error
E/RecyclerView: No adapter attached; skipping layout
I have created an adapter for my recyclerview but the layout does not display. The php backend is working fine. Can somebody please help. Here are my codes for the fragment and adapter
Tips.java
public class Tips extends Fragment {
Configuration config = new Configuration();
String HttpUrl = config.viewtips_url;
List<TipModel> tipList;
RecyclerView recyclerView;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_tips, container, false);
recyclerView = view.findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
tipList = new ArrayList<>();
loadTips();
return view;
}
private void loadTips() {
StringRequest stringRequest = new StringRequest(Request.Method.GET, HttpUrl,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
try {
JSONArray jsonArray = new JSONArray(response);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
tipList.add(new TipModel(
jsonObject.getInt("id"),
jsonObject.getString("tip")
));
}
TipAdapter tipAdapter = new TipAdapter(getActivity(), tipList);
recyclerView.setAdapter(tipAdapter);
} catch (JSONException e) {
e.printStackTrace();
}
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
}
});
Volley.newRequestQueue(getActivity()).add(stringRequest);
}
TipAdapter.java
public class TipAdapter extends RecyclerView.Adapter<TipAdapter.TipViewHolder> {
private Context context;
private List<TipModel> tipList;
public TipAdapter(Context context, List<TipModel> tipList) {
this.context = context;
this.tipList = tipList;
}
@Override
public TipViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(R.layout.itemlayout, null);
return new TipViewHolder(view);
}
@Override
public void onBindViewHolder(TipViewHolder holder, int position) {
TipModel tipModel = tipList.get(position);
holder.textViewTip.setText(tipModel.getTip());
}
@Override
public int getItemCount() {
return tipList.size();
}
class TipViewHolder extends RecyclerView.ViewHolder {
TextView textViewTip;
public TipViewHolder(View view) {
super(view);
textViewTip = view.findViewById(R.id.textViewTip);
}
}
Upvotes: 0
Views: 3132
Reputation: 1
This is how I did it, when I had a similar problem while inflating recycler view in fragment. This code worked perfectly for me:
P.S. - This is the patch of code what I used in my application. I am sorry for any inconvenience.
First of all, in the onCreateView() of your Display Fragment:
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_home, container, false);
Firebase.setAndroidContext(getActivity());
((Home_Drawer) getActivity())
.setActionBarTitle("Home");
recyclerView = (RecyclerView) root.findViewById(R.id.recycler_view_home_frag);
progressBar = (ProgressBar) root.findViewById(R.id.mainPageProgressBar);
// Log.i("inside", "rv initiated" +mLayoutManager.toString());
// Assign activity this to progress dialog.
progressDialog = new ProgressDialog(getActivity());
// Setting up message in Progress dialog.
progressDialog.setMessage("Loading Images From Firebase.");
// Showing progress dialog.
progressDialog.show();
// The path is already defined in MainActivity.
databaseReference = FirebaseDatabase.getInstance().getReference().child("productDisplay");
Log.i("inside", databaseReference.toString());
return root;
}
Then, we call onStart(). This is because recycler view generally does not inflate, ehile setting the adapter in onCreateView().
@Override
public void onStart() {
super.onStart();
FirebaseRecyclerOptions<DisplayItemsModel> item_info =
new FirebaseRecyclerOptions.Builder<DisplayItemsModel>()
.setQuery(databaseReference, DisplayItemsModel.class)
.build();
final FirebaseRecyclerAdapter<DisplayItemsModel, ViewHolder> info_adapter =
new FirebaseRecyclerAdapter<DisplayItemsModel, ViewHolder>(item_info) {
@Override
protected void onBindViewHolder(final ViewHolder holder, final int position, final DisplayItemsModel model) {
mContext = getContext();
final DatabaseReference dref = getRef(position).getRef();
Log.i("dref", dref.toString());
// Adding Add Value Event Listener to databaseReference.
dref.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(final DataSnapshot snapshot) {
holder.item_name_single_card.setText(snapshot.child("name").getValue().toString());
holder.price_single_card.setText(snapshot.child("price").getValue().toString());
String image_url = snapshot.child("image").getValue().toString();
Picasso.get().load(image_url).into(holder.thumbnail);
// Continue with your code.
This worked perfectly for me. Hope it solves your problem.
Upvotes: 0
Reputation: 3894
It happens because RecyclerView
is expecting an adapter when dispatching layout on view created, so it is fine if there is no adapter when the view is created, it will just skip the layout part.
If you are worried about the error, then you could set an empty adapter when the view is created:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_tips, container, false);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
recyclerView = view.findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
tipList = new ArrayList<>();
recyclerView.setAdapter(new TipAdapter(getActivity(), tipList));
}
Then adjust your code in the response callback:
@Override
public void onResponse(String response) {
// Instead of setting adapter here...
// TipAdapter tipAdapter = new TipAdapter(getActivity(), tipList);
// recyclerView.setAdapter(tipAdapter);
// Just notify the adapter that tipList has changed.
recyclerView.getAdapter().notifyDataSetChanged();
// ...
}
Upvotes: 0
Reputation: 1367
TipList is the Adapter's datastore, it belongs to the Adapter and not to the Fragment
I have edited your code ( don't have access to Android Studio, doing it in Text Editor, please check for syntax errors )
public class Tips extends Fragment {
Configuration config = new Configuration();
String HttpUrl = config.viewtips_url;
RecyclerView recyclerView;
TipAdapter tipAdapter;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Initialize the Tip Adapter
tipAdapter = new TipAdapter(getActivity());
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_tips, container, false);
recyclerView = view.findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
// Assign the Adapter to recyclerView
recyclerView.setAdapter(tipAdapter);
return view;
}
private void loadTips() {
StringRequest stringRequest = new StringRequest(Request.Method.GET, HttpUrl,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
try {
JSONArray jsonArray = new JSONArray(response);
// Create a new TipList
List<TipModel> tipList = new ArrayList<>();
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
tipList.add(new TipModel(
jsonObject.getInt("id"),
jsonObject.getString("tip")
));
}
tipAdapter.updateWith(tipList)
} catch (JSONException e) {
e.printStackTrace();
}
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
}
});
Volley.newRequestQueue(getActivity()).add(stringRequest);
}
public class TipAdapter extends RecyclerView.Adapter<TipAdapter.TipViewHolder> {
private Context context;
private List<TipModel> tipList = new ArrayList<>();
public TipAdapter(Context context) {
this.context = context;
}
@Override
public TipViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(R.layout.itemlayout, null);
return new TipViewHolder(view);
}
@Override
public void onBindViewHolder(TipViewHolder holder, int position) {
TipModel tipModel = tipList.get(position);
holder.textViewTip.setText(tipModel.getTip());
}
@Override
public int getItemCount() {
return tipList.size();
}
class TipViewHolder extends RecyclerView.ViewHolder {
TextView textViewTip;
public TipViewHolder(View view) {
super(view);
textViewTip = view.findViewById(R.id.textViewTip);
}
}
public updateWith(List<TipModel> tipList) {
this.tipList = tipList;
notifyDataSetChanged();
}
Upvotes: 0