Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Android Android Lists and Adapters (2015) Lists with RecyclerViews Using a Layout Manager

David Batton
David Batton
10,383 Points

Program is crashing when clicking Hourly Button. It is crashing on the mSummaryLabel.setText(hour.getSummary()) line.

During debugging, I can see that the getSummary is returning a string, then it seems to crash when the function is trying to close. Any assistance if pinpointing the problem would be greatly appreciated. This is day 2 of trying to figure out what is causing the problem.

Hour

public class Hour implements Parcelable{ private long mTime; private String mSummary; private double mTemperature; private String mIcon; private String mTimezone;

public Hour() { };


public long getTime() {
    return mTime;
}

public void setTime(long time) {
    mTime = time;
}

public String getSummary() {
    return mSummary;
}

public void setSummary(String summary) {
    mSummary = summary;
}

public int getTemperature() {

    return (int) Math.round(mTemperature);
}


public void setTemperature(double temperature) {
    mTemperature = temperature;
}

public String getIcon() {
    return mIcon;
}

public int getIconID() {
    return Forecast.getIconId(mIcon);
}

public void setIcon(String icon) {
    mIcon = icon;
}

Hour Adapter

public class HourAdapter extends RecyclerView.Adapter<HourAdapter.HourViewHolder> {

private Hour[] mHours;

public HourAdapter(Hour[] hours) {
    mHours = hours;
}

@Override
public HourViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = LayoutInflater.from(parent.getContext())
            .inflate(R.layout.hourly_list_item, parent, false);

    HourViewHolder viewHolder = new HourViewHolder(view);
    return viewHolder;
}

@Override
public void onBindViewHolder(HourViewHolder holder, int position) {
    holder.bindHour(mHours[position]);
}

@Override
public int getItemCount() {
    return mHours.length;
}

public class HourViewHolder extends RecyclerView.ViewHolder {

    public TextView mTimeLabel;
    public TextView mSummaryLabel;
    public TextView mTemperatureLabel;
    public ImageView mIconImageView;

    public HourViewHolder(View itemView) {
        super(itemView);

        mTimeLabel = (TextView) itemView.findViewById(R.id.timeLabel);
        mSummaryLabel = (TextView) itemView.findViewById(R.id.summaryLabel);
        mTemperatureLabel = (TextView) itemView.findViewById(R.id.temperatureLabel);
        mIconImageView = (ImageView) itemView.findViewById(R.id.iconImageView);
    }

    public void bindHour(Hour hour) {
        mTimeLabel.setText(hour.getHour());
        mSummaryLabel.setText(hour.getSummary());
        mTemperatureLabel.setText(hour.getTemperature() + "");
        mIconImageView.setImageResource(hour.getIconID());

    }
}

}

HourlyForecastActivity public class HourlyForecastActivity extends ActionBarActivity {

private Hour[] mHours;

@InjectView(R.id.recyclerView) RecyclerView mRecyclerView;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_hourly_forecast);
    ButterKnife.inject(this);


    Intent intent = getIntent();
    Parcelable[] parcelables = intent.getParcelableArrayExtra(MainActivity.HOURLY_FORECAST);
    mHours = Arrays.copyOf(parcelables, parcelables.length, Hour[].class);

    HourAdapter adapter = new HourAdapter(mHours);
    mRecyclerView.setAdapter(adapter);

    RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
    mRecyclerView.setLayoutManager(layoutManager);

    mRecyclerView.setHasFixedSize(true);
}

}

MainActivity public class MainActivity extends ActionBarActivity {

public static final String TAG = MainActivity.class.getSimpleName();
public static final String DAILY_FORECAST = "DAILY_FORECAST";
public static final String HOURLY_FORECAST = "HOURLY_FORECAST";
private Forecast mForecast;

@InjectView(R.id.timeLabel) TextView mTimeLabel;
@InjectView(R.id.temperatureLabel) TextView mTemperatureLabel;
@InjectView(R.id.humidityValue) TextView mHumidityValue;
@InjectView(R.id.precipValue) TextView mPrecipValue;
@InjectView(R.id.summaryLabel) TextView mSummaryLabel;
@InjectView(R.id.iconImageView) ImageView mIconImageView;
@InjectView(R.id.refreshImageView) ImageView mRefreshImageView;
@InjectView(R.id.progressBar) ProgressBar mProgressBar;

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

    mProgressBar.setVisibility(View.INVISIBLE);

    final double latitude = 37.8267;
    final double longitude = -122.423;

    mRefreshImageView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            getForecast(latitude, longitude);
        }
    });

    getForecast(latitude, longitude);

    Log.d(TAG, "Main UI code is running!");
}

private void getForecast(double latitude, double longitude) {
    String apiKey = "27974c4bc33201748eaf542a6769c3b7";
    String forecastUrl = "https://api.forecast.io/forecast/" + apiKey +
            "/" + latitude + "," + longitude;

    if (isNetworkAvailable()) {
        toggleRefresh();

        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url(forecastUrl)
                .build();

        Call call = client.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Request request, IOException e) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        toggleRefresh();
                    }
                });
                alertUserAboutError();
            }

            @Override
            public void onResponse(Response response) throws IOException {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        toggleRefresh();
                    }
                });

                try {
                    String jsonData = response.body().string();
                    Log.v(TAG, jsonData);
                    if (response.isSuccessful()) {
                        mForecast = parseForecastDetails(jsonData);
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                updateDisplay();
                            }
                        });
                    } else {
                        alertUserAboutError();
                    }
                } catch (IOException e) {
                    Log.e(TAG, "Exception caught: ", e);
                } catch (JSONException e) {
                    Log.e(TAG, "Exception caught: ", e);
                }
            }
        });
    }
    else {
        Toast.makeText(this, getString(R.string.network_unavailable_message),
                Toast.LENGTH_LONG).show();
    }
}

private void toggleRefresh() {
    if (mProgressBar.getVisibility() == View.INVISIBLE) {
        mProgressBar.setVisibility(View.VISIBLE);
        mRefreshImageView.setVisibility(View.INVISIBLE);
    }
    else {
        mProgressBar.setVisibility(View.INVISIBLE);
        mRefreshImageView.setVisibility(View.VISIBLE);
    }
}

private void updateDisplay() {
    Current current = mForecast.getCurrent();
    mTemperatureLabel.setText(current.getTemperature() + "");
    mTimeLabel.setText("At " + current.getFormattedTime() + " it will be");
    mHumidityValue.setText(current.getHumidity() + "");
    mPrecipValue.setText(current.getPrecipChance() + "%");
    mSummaryLabel.setText(current.getSummary());

    Drawable drawable = getResources().getDrawable(current.getIconId());
    mIconImageView.setImageDrawable(drawable);
}

private Forecast parseForecastDetails(String jsonData) throws JSONException {
    Forecast forecast = new Forecast();

    forecast.setCurrent(getCurrentDetails(jsonData));
    forecast.setHourlyForecast(getHourlyForecast(jsonData));
    forecast.setDailyForecast(getDailyForecast(jsonData));

    return forecast;
}

private Day[] getDailyForecast(String jsonData) throws JSONException {
    JSONObject forecast = new JSONObject(jsonData);
    String timezone = forecast.getString("timezone");

    JSONObject daily = forecast.getJSONObject("daily");
    JSONArray data = daily.getJSONArray("data");

    Day[] days = new Day[data.length()];

    for (int i = 0; i < data.length(); i++) {
        JSONObject jsonDay = data.getJSONObject(i);
        Day day = new Day();

        day.setSummary(jsonDay.getString("summary"));
        day.setTemperatureMax(jsonDay.getDouble("temperatureMax"));
        day.setIcon(jsonDay.getString("icon"));
        day.setTime(jsonDay.getLong("time"));
        day.setTimezone(timezone);

        days[i] = day;
    }

    return days;

}

private Hour[] getHourlyForecast(String jsonData) throws JSONException {
    JSONObject forecast = new JSONObject(jsonData);
    String timezone = forecast.getString("timezone");
    JSONObject hourly = forecast.getJSONObject("hourly");
    JSONArray data = hourly.getJSONArray("data");

    Hour[] hours = new Hour[data.length()];

    for (int i = 0; i < data.length(); i++) {
        JSONObject jsonHour = data.getJSONObject(i);
        Hour hour = new Hour();

        hour.setSummary(jsonHour.getString("summary"));
        hour.setTemperature(jsonHour.getDouble("temperature"));
        hour.setIcon(jsonHour.getString("icon"));
        hour.setTime(jsonHour.getLong("time"));
        hour.setTimezone(timezone);

        hours[i] = hour;
    }
    return hours;
}

private Current getCurrentDetails(String jsonData) throws JSONException {
    JSONObject forecast = new JSONObject(jsonData);
    String timezone = forecast.getString("timezone");
    Log.i(TAG, "From JSON: " + timezone);

    JSONObject currently = forecast.getJSONObject("currently");

    Current current = new Current();
    current.setHumidity(currently.getDouble("humidity"));
    current.setTime(currently.getLong("time"));
    current.setIcon(currently.getString("icon"));
    current.setPrecipChance(currently.getDouble("precipProbability"));
    current.setSummary(currently.getString("summary"));
    current.setTemperature(currently.getDouble("temperature"));
    current.setTimeZone(timezone);

    Log.d(TAG, current.getFormattedTime());

    return current;
}


private boolean isNetworkAvailable() {
    ConnectivityManager manager = (ConnectivityManager)
            getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo networkInfo = manager.getActiveNetworkInfo();
    boolean isAvailable = false;
    if (networkInfo != null && networkInfo.isConnected()) {
        isAvailable = true;
    }

    return isAvailable;
}

private void alertUserAboutError() {
    AlertDialogFragment dialog = new AlertDialogFragment();
    dialog.show(getFragmentManager(), "error_dialog");
}

@OnClick (R.id.dailyButton)
public void startDailyActivity(View view) {
    Intent intent = new Intent(this,DailyForecastActivty.class);
    intent.putExtra(DAILY_FORECAST, mForecast.getDailyForecast());
    startActivity(intent);
}

@OnClick (R.id.hourlyButton)
public void startHourlyActivity(View view) {
    Intent intent = new Intent(this, HourlyForecastActivity.class);
    intent.putExtra(HOURLY_FORECAST, mForecast.getHourlyForecast());
    startActivity(intent);
}

}

David Batton
David Batton
10,383 Points

P.S. I forgot to post the logcat....

08-08 10:21:20.300 1978-1978/teamtreehouse.com.stormy I/art﹕ Not late-enabling -Xcheck:jni (already on) 08-08 10:21:20.450 1978-1978/teamtreehouse.com.stormy D/MainActivity﹕ Main UI code is running! 08-08 10:21:20.455 1978-1990/teamtreehouse.com.stormy I/art﹕ Background sticky concurrent mark sweep GC freed 4124(252KB) AllocSpace objects, 0(0B) LOS objects, 23% free, 850KB/1117KB, paused 21.316ms total 32.109ms 08-08 10:21:20.455 1978-1994/teamtreehouse.com.stormy D/OpenGLRenderer﹕ Use EGL_SWAP_BEHAVIOR_PRESERVED: true 08-08 10:21:20.476 1978-1978/teamtreehouse.com.stormy D/﹕ HostConnection::get() New Host Connection established 0xb42b3f80, tid 1978 08-08 10:21:20.502 1978-1978/teamtreehouse.com.stormy D/Atlas﹕ Validating map... 08-08 10:21:20.588 1978-1994/teamtreehouse.com.stormy D/﹕ HostConnection::get() New Host Connection established 0xb43fb330, tid 1994 08-08 10:21:20.591 1978-1994/teamtreehouse.com.stormy I/OpenGLRenderer﹕ Initialized EGL, version 1.4 08-08 10:21:20.610 1978-1994/teamtreehouse.com.stormy D/OpenGLRenderer﹕ Enabling debug mode 0 08-08 10:21:20.638 1978-1994/teamtreehouse.com.stormy W/EGL_emulation﹕ eglSurfaceAttrib not implemented 08-08 10:21:20.638 1978-1994/teamtreehouse.com.stormy W/OpenGLRenderer﹕ Failed to set EGL_SWAP_BEHAVIOR on surface 0xb431de40, error=EGL_SUCCESS 08-08 10:21:21.125 1978-1993/teamtreehouse.com.stormy V/MainActivity﹕ {"latitude":37.8267,"longitude":-122.423,"timezone":"America/Los_Angeles","offset":-7,"currently":{"time":1439043705,"summary":"Overcast","icon":"cloudy","nearestStormDistance":170,"nearestStormBearing":52,"precipIntensity":0,"precipProbability":0,"temperature":59.55,"apparentTemperature":59.55,"dewPoint":54.5,"humidity":0.83,"windSpeed":9.28,"windBearing":256,"visibility":6.83,"cloudCover":0.96,"pressure":1012.7,"ozone":325.52},"minutely":{"summary":"Overcast for the hour.","icon":"cloudy","data":[{"time":1439043660,"precipIntensity":0,"precipProbability":0},{"time":1439043720,"precipIntensity":0,"precipProbability":0},{"time":1439043780,"precipIntensity":0,"precipProbability":0},{"time":1439043840,"precipIntensity":0,"precipProbability":0},{"time":1439043900,"precipIntensity":0,"precipProbability":0},{"time":1439043960,"precipIntensity":0,"precipProbability":0},{"time":1439044020,"precipIntensity":0,"precipProbability":0},{"time":1439044080,"precipIntensity":0,"precipProbability":0},{"time":1439044140,"precipIntensity":0,"precipProbability":0},{"time":1439044200,"precipIntensity":0,"precipProbability":0},{"time":1439044260,"precipIntensity":0,"precipProbability":0},{"time":1439044320,"precipIntensity":0,"precipProbability":0},{"time":1439044380,"precipIntensity":0,"precipProbability":0},{"time":1439044440,"precipIntensity":0,"precipProbability":0},{"time":1439044500,"precipIntensity":0,"precipProbability":0},{"time":1439044560,"precipIntensity":0,"precipProbability":0},{"time":1439044620,"precipIntensity":0,"precipProbability":0},{"time":1439044680,"precipIntensity":0,"precipProbability":0},{"time":1439044740,"precipIntensity":0,"precipProbability":0},{"time":1439044800,"precipIntensity":0,"precipProbability":0},{"time":1439044860,"precipIntensity":0,"precipProbability":0},{"time":1439044920,"precipIntensity":0,"precipProbability":0},{"time":1439044980,"precipIntensity":0,"precipProbability":0},{"time":1439045040,"precipIntensity":0,"precipProbability":0},{"time":1439045100,"precipIntensity":0,"precipProbability":0},{"time":1439045160,"precipIntensity":0,"precipProbability":0},{"time":1439045220,"precipIntensity":0,"precipProbability":0},{"time":1439045280,"precipIntensity":0,"precipProbability":0},{"time":1439045340,"precipIntensity":0,"precipProbability":0},{"time":1439045400,"precipIntensity":0,"precipProbability":0},{"time":1439045460,"precipIntensity":0,"precipProbability":0},{"time":1439045520,"precipIntensity":0,"precipProbability":0},{"time":1439045580,"precipIntensity":0,"precipProbability":0},{"time":1439045640,"precipIntensity":0,"precipProbability":0},{"time":1439045700,"precipIntensity":0,"precipProbability":0},{"time":1439045760,"precipIntensity":0,"precipProbability":0},{"time":1439045820,"precipIntensity":0,"precipProbability":0},{"time":1439045880,"precipIntensity":0,"precipProbability":0},{"time":1439045940,"precipIntensity":0,"precipProbability":0},{"time":1439046000,"precipIntensity":0,"precipProbability":0},{"time":1439046060,"precipIntensity":0,"precipProbability":0},{"time":1439046120,"precipIntensity":0,"precipProbability":0},{"time":1439046180,"precipIntensity":0,"precipProbability":0},{"time":1439046240,"precipIntensity":0,"precipProbability":0},{"time":1439046300,"precipIntensity":0,"precipProbability":0},{"time":1439046360,"precipIntensity":0,"precipProbability":0},{"time":1439046420,"precipIntensity":0,"precipProbability":0},{"time":1439046480,"precipIntensity":0,"precipProbability":0},{"time":1439046540,"precipIntensity":0,"precipProbability":0},{"time":1439046600,"precipIntensity":0,"precipProbability":0},{"time":1439046660,"precipIntensity":0,"precipProbability":0},{"time":1439046720,"precipIntensity":0,"precipProbability":0},{"time":1439046780,"precipIntensity":0,"precipProbability":0},{"time":1439046840,"precipIntensity":0,"precipProbability":0},{"time":1439046900,"precipIntensity":0,"precipProbability":0},{"time":1439046960,"precipIntensity":0,"precipProbability":0},{"time":1439047020,"precipIntensity":0,"precipProbability":0},{"time":1439047080,"pre 08-08 10:21:21.133 1978-1993/teamtreehouse.com.stormy I/MainActivity﹕ From JSON: America/Los_Angeles 08-08 10:21:21.134 1978-1993/teamtreehouse.com.stormy D/MainActivity﹕ 7:21 AM 08-08 10:21:21.184 1978-1990/teamtreehouse.com.stormy W/art﹕ Suspending all threads took: 8.017ms 08-08 10:21:21.212 1978-1990/teamtreehouse.com.stormy I/art﹕ Background sticky concurrent mark sweep GC freed 30991(1110KB) AllocSpace objects, 2(71KB) LOS objects, 24% free, 1380KB/1832KB, paused 9.379ms total 84.226ms 08-08 10:21:21.340 1978-1978/teamtreehouse.com.stormy I/Choreographer﹕ Skipped 38 frames! The application may be doing too much work on its main thread. 08-08 10:21:23.333 1978-1994/teamtreehouse.com.stormy W/EGL_emulation﹕ eglSurfaceAttrib not implemented 08-08 10:21:23.333 1978-1994/teamtreehouse.com.stormy W/OpenGLRenderer﹕ Failed to set EGL_SWAP_BEHAVIOR on surface 0xa497a4c0, error=EGL_SUCCESS 08-08 10:21:23.343 1978-1978/teamtreehouse.com.stormy D/AndroidRuntime﹕ Shutting down VM --------- beginning of crash 08-08 10:21:23.343 1978-1978/teamtreehouse.com.stormy E/AndroidRuntime﹕ FATAL EXCEPTION: main Process: teamtreehouse.com.stormy, PID: 1978 java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference at teamtreehouse.com.stormy.adapters.HourAdapter$HourViewHolder.bindHour(HourAdapter.java:61) at teamtreehouse.com.stormy.adapters.HourAdapter.onBindViewHolder(HourAdapter.java:35) at teamtreehouse.com.stormy.adapters.HourAdapter.onBindViewHolder(HourAdapter.java:16) at android.support.v7.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:4138) at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:3448) at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:3340) at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:1810) at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1306) at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1269) at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:523) at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:1988) at android.support.v7.widget.RecyclerView.onLayout(RecyclerView.java:2237) at android.view.View.layout(View.java:15671) at android.view.ViewGroup.layout(ViewGroup.java:5038) at android.widget.RelativeLayout.onLayout(RelativeLayout.java:1076) at android.view.View.layout(View.java:15671) at android.view.ViewGroup.layout(ViewGroup.java:5038) at android.widget.FrameLayout.layoutChildren(FrameLayout.java:579) at android.widget.FrameLayout.onLayout(FrameLayout.java:514) at android.view.View.layout(View.java:15671) at android.view.ViewGroup.layout(ViewGroup.java:5038) at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1703) at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1557) at android.widget.LinearLayout.onLayout(LinearLayout.java:1466) at android.view.View.layout(View.java:15671) at android.view.ViewGroup.layout(ViewGroup.java:5038) at android.widget.FrameLayout.layoutChildren(FrameLayout.java:579) at android.widget.FrameLayout.onLayout(FrameLayout.java:514) at android.view.View.layout(View.java:15671) at android.view.ViewGroup.layout(ViewGroup.java:5038) at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1703) at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1557) at android.widget.LinearLayout.onLayout(LinearLayout.java:1466) at android.view.View.layout(View.java:15671) at android.view.ViewGroup.layout(ViewGroup.java:5038) at android.widget.FrameLayout.layoutChildren(FrameLayout.java:579) at android.widget.FrameLayout.onLayout(FrameLayout.java:514) at android.view.View.layout(View.java:15671) at android.view.ViewGroup.layout(ViewGroup.java:5038) at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2086) at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1843) at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1061) at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5885) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:767) at android.view.Choreographer.doCallbacks(Choreographer.java:580) at android.view.Choreographer.doFrame(Choreographer.java:550) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:753) at android.os.Handler.handleCallback(Handler.java:739) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:135) at android.app.ActivityThread.main(ActivityThread.java:5257) at java.lang.reflect.Method.invoke(Native Method) at java.lang.reflect.Method.invoke(Method.java:372) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698) 08-08 10:21:25.625 1978-1978/? I/Process﹕ Sending signal. PID: 1978 SIG: 9

1 Answer

Jacob Biros
Jacob Biros
2,241 Points

First off, any chance you can post this with line numbers or on github? Its hard to see what the logcat is referencing.

Maybe a dumb question, but did you set the id on your summaryLabel? Mine wasn't set and I think it was giving me a similar error.