-1

I'm getting the error:

RecyclerView﹕ No adapter attached; skipping layout

I checked some other answers people have given for this issue, but had no luck.

Adapter:

public class MyAdapter extends RecyclerView.Adapter<com.example.myapplication.MyAdapter.MyViewHolder> {

    private Context context;
    private List<HeadlineModel> headlineModelList;

    public MyAdapter(Context context, List<HeadlineModel> headlineModelList) {
        this.context = context;
        this.headlineModelList = headlineModelList;
    }

    @NonNull
    @Override
    public com.example.myapplication.MyAdapter.MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view= LayoutInflater.from(context).inflate(R.layout.news_item_layout,parent,false);
        return new MyViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull final com.example.myapplication.MyAdapter.MyViewHolder holder, int position) {
        final HeadlineModel headlineModel=headlineModelList.get(position);
        holder.newTitle.setText(headlineModel.getTitle());
        holder.newsDescription.setText(headlineModel.getDescription());
        holder.newsDescription.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Uri uri= Uri.parse(headlineModel.getUrl());
                Intent intent = new Intent(Intent.ACTION_VIEW, uri);
                context.startActivity(intent);
                //Log.v("SSSSSS",headlineModel.getUrl());
            }
        });
        holder.newsName.setText(headlineModel.getName());
        holder.newsTime.setText(headlineModel.getPublishedAt());
        Glide.with(context).load(headlineModel.getUrlToImage())
                .thumbnail(0.5f)
                .into(holder.newsImage);
    }

    @Override
    public int getItemCount() {
        return headlineModelList.size();
    }

    public class MyViewHolder extends RecyclerView.ViewHolder {
        TextView newTitle;
        TextView newsDescription;
        TextView newsName;
        TextView newsTime;
        ImageView newsImage;

        public MyViewHolder(@NonNull View itemView) {
            super(itemView);
            newTitle=itemView.findViewById(R.id.tv_news_title);
            newsDescription=itemView.findViewById(R.id.tv_news_desc);
            newsName=itemView.findViewById(R.id.tv_name);
            newsTime=itemView.findViewById(R.id.tv_news_date);
            newsImage=itemView.findViewById(R.id.im_news_image);
        }
    }
}

The recycler view in onCreateView in my fragment is initialized like this:

RecyclerView recyclerView;
    com.example.myapplication.MyAdapter myAdapter;
    private ProgressDialog progressDialog;

    List<com.example.myapplication.HeadlineModel> headlineModelList;

    private static final String URL="http://newsapi.org/v2/top-headlines?country=in&apiKey=cbd46bd6a4f54fe69d0cb261dbe1a878";

    public HeadlinesFragment() {
        // Required empty public constructor
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        View rootview=inflater.inflate(R.layout.fragment_headlines, container, false);
        // Inflate the layout for this fragment

        recyclerView=rootview.findViewById(R.id.headRecyclerView);
        headlineModelList=new ArrayList<>();
        recyclerView.setHasFixedSize(true);
        recyclerView.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL,false));

        progressDialog=new ProgressDialog(getContext(),R.style.ProgressColor);
        progressDialog.setMessage("loading...");
        progressDialog.show();
        loadData();
        return rootview;
    }

loadData() function that is called

private void loadData() {
        progressDialog.setMessage("Loading data...");
        //progressDialog.show();

        JsonObjectRequest jsonObjectRequest=new JsonObjectRequest(Request.Method.GET, URL, null, new Response.Listener<JSONObject>() {
            @Override
            public void onResponse(JSONObject response) {
                progressDialog.dismiss();
                try {
                    JSONArray jsonArray=response.getJSONArray("articles");
                    for (int i=0;i<jsonArray.length();i++){
                        JSONObject jsonObject=jsonArray.getJSONObject(i);
                        String title=jsonObject.getString("title");
                        String desc=jsonObject.getString("description");
                        String url=jsonObject.getString("url");
                        String urlToImage=jsonObject.getString("urlToImage");
                        String publishedAt=jsonObject.getString("publishedAt");
                        JSONObject source=jsonObject.getJSONObject("source");
                        String name=source.getString("name");

                        // for formatting time and date //

                        String year=publishedAt.substring(0,4);
                        String month=publishedAt.substring(5,7);
                        String date=publishedAt.substring(8,10);
                        String hour=publishedAt.substring(11,13);

                        //String hour="11";
                        String min=publishedAt.substring(14,16);
                        //Log.v("XXXXXX",min);
                        String updatedDate=date.concat("-").concat(month).concat("-").concat(year).concat("  ");
                        String print="";
                        int convertHour= Integer.parseInt(hour);
                        int convertMin= Integer.parseInt(min);
                        if (convertHour==12) {
                            convertHour=12;
                            print="PM";
                        }
                        else if (convertHour>11&&convertMin>0){
                            convertHour=convertHour-12;
                            print="PM";
                        }else {
                            print="AM";
                        }
                        String newHour= String.valueOf(convertHour);
                        String updatedTime=updatedDate.concat(newHour).concat(":").concat(min).concat(" ").concat(print);


                        myAdapter=new com.example.myapplication.MyAdapter(getContext(),headlineModelList);
                        com.example.myapplication.HeadlineModel headlineModel=new com.example.myapplication.HeadlineModel(name,title,desc,url,urlToImage,updatedTime);
                        headlineModelList.add(headlineModel);
                        recyclerView.setAdapter(myAdapter);
                        myAdapter.notifyDataSetChanged();
                    }

                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {

            }
        })
        {
            @Override
            protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
                try {
                    Cache.Entry cacheEntry = HttpHeaderParser.parseCacheHeaders(response);
                    if (cacheEntry == null) {
                        cacheEntry = new Cache.Entry();
                    }
                    final long cacheHitButRefreshed = 3 * 60 * 1000; // in 3 minutes cache will be hit, but also refreshed on background
                    final long cacheExpired = 24 * 60 * 60 * 1000; // in 24 hours this cache entry expires completely
                    long now = System.currentTimeMillis();
                    final long softExpire = now + cacheHitButRefreshed;
                    final long ttl = now + cacheExpired;
                    cacheEntry.data = response.data;
                    cacheEntry.softTtl = softExpire;
                    cacheEntry.ttl = ttl;
                    String headerValue;
                    headerValue = response.headers.get("Date");
                    if (headerValue != null) {
                        cacheEntry.serverDate = HttpHeaderParser.parseDateAsEpoch(headerValue);
                    }
                    headerValue = response.headers.get("Last-Modified");
                    if (headerValue != null) {
                        cacheEntry.lastModified = HttpHeaderParser.parseDateAsEpoch(headerValue);
                    }
                    cacheEntry.responseHeaders = response.headers;
                    final String jsonString = new String(response.data,
                            HttpHeaderParser.parseCharset(response.headers));
                    return Response.success(new JSONObject(jsonString), cacheEntry);
                } catch (UnsupportedEncodingException | JSONException e) {
                    return Response.error(new ParseError(e));
                }
            }

            @Override
            protected void deliverResponse(JSONObject response) {
                super.deliverResponse(response);
            }

            @Override
            public void deliverError(VolleyError error) {
                super.deliverError(error);
            }

            @Override
            protected VolleyError parseNetworkError(VolleyError volleyError) {
                return super.parseNetworkError(volleyError);
            }
        };

        RequestQueue queue= Volley.newRequestQueue(getContext());
        queue.add(jsonObjectRequest);

    }

Does anyone know what I'm doing wrong?

  • Write a few logs statement. first before attaching the adapter to identify if you are receiving the data or not then in onBindViewHolder to identify if the data is coming to RecyclerView or not. – Vijay Apr 28 '21 at 03:46
  • Does this answer your question? [recyclerview No adapter attached; skipping layout](https://stackoverflow.com/questions/29141729/recyclerview-no-adapter-attached-skipping-layout) – Mohammed Abid Nafi Apr 28 '21 at 07:58

2 Answers2

0

Set the Adapter before the API call success because your API response is async and till will take time depending upon response size, network speed etc, till that time recycler view needs to be created and it is having no adapter. You can set adaptor before calling loadData() and later when you get the list of response set the data in the adapter of your recylerview and call notify on the adapter.

Dinkar Kumar
  • 2,175
  • 2
  • 12
  • 22
0

myAdapter=new com.example.myapplication.MyAdapter(getContext(),headlineModelList); recyclerView.setAdapter(myAdapter);

use it on onCreateView method and myAdapter.notifyDataSetChanged(); use it when API success