androidandroid-studioandroid-fragmentsoncreatefragment-oncreateview

No Adapter Attached, Skipping Layout on Fragment


I've tried a few different ways of fixing this, but it just doesn't seem to want to work. I have attached the fragment involved. The recyclerview works when I use the search function; However, when I first load the page, I get the error that

E/RecyclerView: No adapter attached; skipping layout

I think it might be an issue with the onCreate vs onCreateView, but I'm not exactly sure what to put where.

NewsFragment.java



    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment

        v = inflater.inflate(R.layout.fragment_news, container, false);
        swipeRefreshLayout = v.findViewById(R.id.swipeRefresh);
        recyclerView = v.findViewById(R.id.news_recyclerView);


        etQuery = v.findViewById(R.id.etQuery);
        btnSearch = v.findViewById(R.id.btnSearch);

        recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));

        final String country = getCountry();

        swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                retrieveJson("", country, API_KEY);
            }
        });
        retrieveJson("", country, API_KEY);


        btnSearch.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (!etQuery.getText().toString().equals("")) {
                    swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
                        @Override
                        public void onRefresh() {
                            retrieveJson(etQuery.getText().toString(), country, API_KEY);
                        }
                    });
                    retrieveJson(etQuery.getText().toString(), country, API_KEY);
                } else {
                    swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
                        @Override
                        public void onRefresh() {
                            retrieveJson("", country, API_KEY);
                        }
                    });
                    retrieveJson("", country, API_KEY);
                }
            }
        });
        return v;

    }

    public void retrieveJson(String query ,String country, String apiKey){

        swipeRefreshLayout.setRefreshing(true);
        Call<Headlines> call;
        if (!etQuery.getText().toString().equals("")){
            call=NewsApiClient.getInstance().getApi().getSpecificData(query,apiKey);

        }else{
            call=NewsApiClient.getInstance().getApi().getHeadlines(country,apiKey);
        }

        call.enqueue(new Callback<Headlines>() {
            @Override
            public void onResponse(Call<Headlines> call, Response<Headlines> response) {
                if (response.isSuccessful() && response.body().getArticles() != null ){
                    swipeRefreshLayout.setRefreshing(false);
                    articles.clear();
                    articles = response.body().getArticles();
                    newsAdapter = new NewsAdapter(getContext(), articles);
                    recyclerView.setAdapter(newsAdapter);
                }
            }

            @Override
            public void onFailure(Call<Headlines> call, Throwable t) {
                swipeRefreshLayout.setRefreshing(false);
                Toast.makeText(getContext(), t.getLocalizedMessage(), Toast.LENGTH_SHORT).show();
            }
        });

    }

    public String getCountry(){
        Locale locale = Locale.getDefault();
        String country = locale.getCountry();
        return country.toLowerCase();
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);


    }


}

Solution

  • On the onCreateView you are in fact not setting any adapter. You instead set it when retrieving the json data inside the call.enqueue callbacks, this callbacks are called asynchronously and thus the first time the onCreateView is called no adapter is set to the RecyclerView. To avoid that, set an adapter with empty data empty adapter right at the start of the onCreateView function like this (make newsAdapter a variable of the current fragment)

    recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
    newsAdapter = new NewsAdapter(getContext(), articles);
    recyclerView.setAdapter(newsAdapter);
    

    make articles be a variable of the current fragment and insted of setting and adapter on the callbacks of you retriveJson function simply update the articles array with the data and call the notifydatasetchanged function of the RecycleView like this

    public void onResponse(Call<Headlines> call, Response<Headlines> response) {
       if (response.isSuccessful() && response.body().getArticles() != null ){
          swipeRefreshLayout.setRefreshing(false);
          articles.clear();
          articles = response.body().getArticles();
          newsAdapter.setData(articles);
          newsAdapter.notifyDataSetChanged()
       }
    }
    

    setData is a function that you have to create in your NewsAdapter class. Hope it helped! And take a look a this brief guide on how to use RecycleViews