Search code examples
androidandroid-recyclerviewadapter

Android - RecyclerView: No adapter attached; skipping layout Error


I'm coding an app that shows the rrank of boxoffice by receiving API of Json file everything works fine if I comment the codes about Recyclerview. Adapter code is fine I guess...................................................................................................................................................... if not, logcat says like this:

08-03 09:53:59.915 8189-8189/kr.ac.mju.mju_alimi E/RecyclerView: No adapter attached; skipping layout
08-03 09:54:00.351 8189-8189/kr.ac.mju.mju_alimi E/AndroidRuntime: FATAL EXCEPTION: main
    Process: kr.ac.mju.mju_alimi, PID: 8189
    java.lang.NullPointerException: Attempt to get length of null array
        at kr.ac.mju.mju_alimi.MainActivity$MyAsyncTask.onPostExecute(MainActivity.java:152)
        at kr.ac.mju.mju_alimi.MainActivity$MyAsyncTask.onPostExecute(MainActivity.java:97)

I think the order of the codes is wrong, but don't know exactly... MainActivity.java is... :

public class MainActivity extends AppCompatActivity {


    public static final String TAG = "MainActivity";
    TextView tv_result;

    private RecyclerView mRecyclerView;
    private RecyclerView.Adapter mAdapter;
    private RecyclerView.LayoutManager mLayoutManager;

    ArrayList<MovieItem> itemArrayList;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        //array list
        itemArrayList = new ArrayList<>(); //데이터

        mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
        mLayoutManager = new LinearLayoutManager(this);
        mRecyclerView.setHasFixedSize(true);
        mRecyclerView.setLayoutManager(mLayoutManager);

//        tv_result = (TextView) findViewById(R.id.tv_result);
//        tv_result.setMovementMethod(new ScrollingMovementMethod()); //스크롤기능 추가하기

        MyAsyncTask mProcessTask = new MyAsyncTask();
        mProcessTask.execute();


        android.support.v7.widget.Toolbar toolbar = (android.support.v7.widget.Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayShowTitleEnabled(false);

        toolbar.findViewById(R.id.menu).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                PopupMenu pop = new PopupMenu(MainActivity.this, v);
                pop.getMenuInflater().inflate(R.menu.menu, pop.getMenu());
                pop.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
                    @Override
                    public boolean onMenuItemClick(MenuItem item) {
                        return false;
                    }
                });
                pop.show();
            }

        });

        ImageButton b = (ImageButton) findViewById(R.id.bell);
        b.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(MainActivity.this, Pop.class));
            }
        });

    }


    //AsyncTask 생성 - 모든 네트워크 로직을 여기서 작성해 준다.
    public class MyAsyncTask extends AsyncTask<String, Void, MovieItem[]> {
        ProgressDialog progressDialog = new ProgressDialog(MainActivity.this);

        //OkHttp 객체생성
        OkHttpClient client = new OkHttpClient();

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
            progressDialog.setMessage("\t로딩중...");
            //show dialog
            progressDialog.show();
        }

        @Override
        protected MovieItem[] doInBackground(String... params) {

            HttpUrl.Builder urlBuilder = HttpUrl.parse("http://www.kobis.or.kr/kobisopenapi/webservice/rest/boxoffice/searchDailyBoxOfficeList.json").newBuilder();
            urlBuilder.addQueryParameter("key","430156241533f1d058c603178cc3ca0e");
            urlBuilder.addQueryParameter("targetDt","20170908");
            String url = urlBuilder.build().toString();

            Request request = new Request.Builder()
                    .url(url)
                    .build();

            try {
                Response response = client.newCall(request).execute();

                Gson gson = new GsonBuilder().create();
                JsonParser parser = new JsonParser();


                JsonElement rootObject = parser.parse(response.body().charStream())
                        .getAsJsonObject().get("boxOfficeResult").getAsJsonObject().get("dailyBoxOfficeList"); 
                MovieItem[] posts = gson.fromJson(rootObject, MovieItem[].class);

                return posts;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }

        @Override
        protected void onPostExecute(MovieItem[] result) {
            super.onPostExecute(result);
            progressDialog.dismiss();

            if(result.length > 0){
                for (MovieItem post: result){
                    itemArrayList.add(post);

                }
            }

            mAdapter = new Adapter(itemArrayList);
            mRecyclerView.setAdapter(mAdapter);
        }
    }

}

Solution

  • You are setting the adapter after the call of the async task. Meaning, every time the async task is called, the adapter of the recycler view gets changed. Which is not necessary since you are only using a single adapter. What would be best is to initialize the adapter onCreate then just notify the adapter that its dataset have changed when you have changed the values of the list.


    TL;DR

    Move this code to your on create:

    mAdapter = new Adapter(itemArrayList);
    mRecyclerView.setAdapter(mAdapter);
    

    And replace this from where that code originally was(P.S. use intellisense to figure out if thats the right function, the keywords are notify, dataset and changed):

    mAdapter.notifyDataSetChanged()