ruatemem
ruatemem

Reputation: 57

Fragment, RecyclerView: No adapter attached; skipping layout

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

Answers (3)

burhan_kangsi
burhan_kangsi

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

Aaron
Aaron

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

anemo
anemo

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 )

Fragment

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);
}

TipAdapter

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

Related Questions