android – List<Model> null when passing it to nested Adapter-ThrowExceptions

Exception or error:

Not sure why the list is null when I have added the model to it after setting all the data from network call.

If I use finalHourList the data shows in the log if I print to logcat. I can’t use finalHourList as I have tied it to the HourlyForcast model inside the adapter also. So, I can’t pass the adapter a string and have to pass it a List<HourlyForcast>. Not sure why finalHourList.add(forecast); is null after I have set data to forecast.

The hardcoded list works with no issues, but now I am trying to populate the RecyclerView with the data coming back from the network call.

public class HomeRecyclerAdapter extends RecyclerView.Adapter<HomeRecyclerAdapter.ViewHolder> {
    private ArrayList<String> dates;
    private Context context;
    private String defaultZipcode = "55372";
    private String mEnglishTemp, mCivilTime, mCondtion, mConditionIcon;
    private List<HourlyForcast> finalHourlyList = new ArrayList<>();
    HourlyForcastAdapter adapter;
    private HourlyForcast forecast;

    public HomeRecyclerAdapter(ArrayList<String> dates) {
        this.dates = dates;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int i) {
        context = parent.getContext();
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.hourly_cardview, parent, false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        Typeface titleStyle = Typeface.createFromAsset(context.getAssets(),
                "font/Roboto-Medium.ttf");
        holder.mDate.setTypeface(titleStyle);
        holder.mDate.setText(dates.get(position));

        getHourlyWeather(defaultZipcode);

        GridLayoutManager gridLayoutManager = new GridLayoutManager(context, 4);
        holder.mInnerRecycler.setHasFixedSize(true);
        holder.mInnerRecycler.setLayoutManager(gridLayoutManager);
        adapter = new HourlyForcastAdapter(context, finalHourlyList);
        holder.mInnerRecycler.setAdapter(adapter);
    }

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

    public static class ViewHolder extends RecyclerView.ViewHolder {
        private TextView mDate;
        private RecyclerView mInnerRecycler;

        ViewHolder(View view) {
            super(view);
            mDate = (TextView) view.findViewById(R.id.tvDate);
            mInnerRecycler = (RecyclerView) view.findViewById(R.id.hourlyRecycler);
        }
    }

    private List<HourlyForcast> getAllItemList() {

        List<HourlyForcast> allHours = new ArrayList<>();
        allHours.add(new HourlyForcast("4:00 PM", "8°", "Overcast"));
        allHours.add(new HourlyForcast("5:00 PM", "6°", "Sunny"));
        allHours.add(new HourlyForcast("6:00 PM", "5°", "Sunny"));
        allHours.add(new HourlyForcast("7:00 PM", "3°", "Rainy"));
        allHours.add(new HourlyForcast("8:00 PM", "3°", "Sunny"));
        allHours.add(new HourlyForcast("9:00 PM", "3°", "Snowing"));
        allHours.add(new HourlyForcast("10:00 PM", "4°", "Sunny"));
        allHours.add(new HourlyForcast("11:00 PM", "60°", "Sunny"));
        return allHours;
    }

    public void getHourlyWeather(String zipCode) {
        OkHttpClient client = new OkHttpClient();

        HttpUrl.Builder urlBuilder = HttpUrl.parse(context.getString
                (R.string.hourlyForcastURL)).newBuilder();
        urlBuilder.addPathSegment(zipCode + ".json");
        String url = urlBuilder.build().toString();

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

        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                e.printStackTrace();
                call.cancel();
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String mResponse = response.body().string();
                try {
                    JSONObject hourlyObject = new JSONObject(mResponse);
                    JSONArray hourForcastArray = hourlyObject.getJSONArray("hourly_forecast");
                    for (int i = 0; i < hourForcastArray.length(); i++) {
                        JSONObject HourlyObject = hourForcastArray.getJSONObject(i);
                        JSONObject mTemp = HourlyObject.getJSONObject("temp");
                        mConditionIcon = HourlyObject.getString("icon_url");
                        mEnglishTemp = mTemp.getString("english");
                        mCondtion = HourlyObject.getString("condition");
                        JSONObject FCTRemoveal = HourlyObject.getJSONObject("FCTTIME");
                        mCivilTime = FCTRemoveal.getString("civil");

                        forecast = new HourlyForcast();
                        forecast.setTime(mCivilTime);
                        forecast.setCondition(mCondtion);
                        forecast.setDegrees(mEnglishTemp);

                        /*finalHourlyList = new ArrayList<>();
                        finalHourlyList.add(mEnglishTemp);
                        finalHourlyList.add(mCivilTime);
                        finalHourlyList.add(mCondtion);*/

                        finalHourlyList = new ArrayList<>();
                        finalHourlyList.add(forecast);
                        Log.i("HOURLYLIST", finalHourlyList.toString());
                    }
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        });
    }
}

Adapter I am passing the list to

public class HourlyForcastAdapter extends RecyclerView.Adapter<HourlyForcastAdapter.HourlyViewHolder> {
    private List<HourlyForcast> itemList;
    private Context context;

    public HourlyForcastAdapter(Context context, List<HourlyForcast> itemList) {
        this.itemList = itemList;
        this.context = context;
    }

    @Override
    public HourlyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.hourly_single, parent, false);
        return new HourlyViewHolder(view);
    }

    @Override
    public void onBindViewHolder(HourlyViewHolder holder, int position) {
        Typeface regStyle = Typeface.createFromAsset(context.getAssets(),
                "font/Roboto-Regular.ttf");
        holder.mTimeText.setTypeface(regStyle);
        holder.mDegreeText.setTypeface(regStyle);
        holder.mTimeText.setText(itemList.get(position).getTime());
        holder.mDegreeText.setText(itemList.get(position).getDegrees());
        holder.mWeatherIcon.setText(itemList.get(position).getCondition());
     //   holder.mWeatherIcon.setImageResource(itemList.get(position).getImageID());
    }

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

    public static class HourlyViewHolder extends RecyclerView.ViewHolder {
        TextView mTimeText, mDegreeText, mWeatherIcon;
      //  ImageView mWeatherIcon;

        public HourlyViewHolder(View itemView) {
            super(itemView);
            mTimeText = (TextView) itemView.findViewById(R.id.timePlaceHolder);
            mDegreeText = (TextView) itemView.findViewById(R.id.degreePlaceHolder);
            mWeatherIcon = (TextView) itemView.findViewById(R.id.weatherIconHolder);
        }
    }
}
How to solve:

Instead of having the network call inside an adapter,place it in the class where you call the HomeRecyclerAdapter say MainActivity. And pass the List in the Constructor of HomeRecyclerAdapter.

In MainActivity

  • final RecyclerView.Adapter adapter = new HomeRecyclerAdapter(days,finalHourlyList);

  • getHourlyWeather(String zipCode)

In HomeRecyclerAdapter

public HomeRecyclerAdapter(ArrayList<String> dates,ArrayList<HourlyForcast> finalHourlyList) {
    this.dates = dates;
    this.finalHourlyList = finalHourlyList;
}

###

alright figured i out, this is what happens.

HourlyForcastAdapter adapter = new HourlyForcastAdapter(context, finalHourlyList); //passing this list to adapter

that line of passes a null reference with no data currently in it. Therefore you initially something empty therefore you get something empty. To remedy this, add a method in the next adapter class, that accepts a finalHourlyList. Then when the network call is finished manually call this method thus passing the newly updated list.

Also in the next adapter, call notifyDataSetChange to signal a refresh.

 adapter.notifyDataSetChanged();

Make sense?
The main reason is because recycler eagerly displays data when a adapter is attached.but there is no data, so it freaks out.

change private List<HourlyForcast> finalHourlyList; to

private List<HourlyForcast> finalHourlyList = new ArrayList<>();

at the very top.

---------------------------------------------------------------------
 forecast = new HourlyForcast();
                    forecast.setTime(mCivilTime);
                    forecast.setCondition(mCondtion);
                    forecast.setDegrees(mEnglishTemp);

                    /*finalHourlyList = new ArrayList<>();
                    finalHourlyList.add(mEnglishTemp);
                    finalHourlyList.add(mCivilTime);
                    finalHourlyList.add(mCondtion);*/

                    finalHourlyList = new ArrayList<>();
                    finalHourlyList.add(forecast);

this line below will work,becuase it is currently populated with data. but what i am saying is this, when you call this line in onBind adapter = new HourlyForcastAdapter(context, finalHourlyList); there is no data yet. what you are thinking is this, becuase i set the data before any changes i make will automatically reflect,but no it wont. You have to trigger a update and let the recycler view know there is new content available.So you need to update the inner recycler view adapter.like this. model this logic.

       holder.mInnerRecycler. adapter.notifyDataSetChanged();

Leave a Reply

Your email address will not be published. Required fields are marked *