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

Josh Gold
Josh Gold
12,207 Points

Attempting to put JSON data from ForecastIO API into an object called mDailyWeather, but mDailyWeather is still null.

I don't quite understand how to retrieve and store the JSON data for daily weather for Forecast IO API. I do understand how to use the current weather information, but the daily weather information is different.

Anyhow I am getting a null pointer exception because the object mDailyWeather is null. Not sure how to get the data into this object.

My end goal is to get the high temperature and low temperature for today.

Screen capture of the debugger results: http://imgur.com/fNsMwYA

MainActivity.java

     package com.joshbgold.stormy;

     import android.content.Context;
     import android.graphics.drawable.Drawable;
     import android.net.ConnectivityManager;
     import android.net.NetworkInfo;
     import android.os.Bundle;
     import android.support.v7.app.ActionBarActivity;
     import android.util.Log;
     import android.view.View;
     import android.widget.ImageView;
     import android.widget.ProgressBar;
     import android.widget.TextView;
     import android.widget.Toast;
     import com.squareup.okhttp.Call;
     import com.squareup.okhttp.Callback;
     import com.squareup.okhttp.OkHttpClient;
     import com.squareup.okhttp.Request;
     import com.squareup.okhttp.Response;
     import org.json.JSONArray;
     import org.json.JSONException;
     import org.json.JSONObject;
     import java.io.IOException;
     import butterknife.ButterKnife;
     import butterknife.InjectView;

     public class MainActivity extends ActionBarActivity {

         public static final String TAG = MainActivity.class.getSimpleName();

    private CurrentWeather mCurrentWeather;
    private Day[] mDailyWeather;

    @InjectView(R.id.timeLabel) TextView mTimeLabel;  //declares time variable, and links it to the layout
    @InjectView(R.id.temperatureLabel) TextView mTempuratureLabel;
    @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.windValue) TextView mWindValue;
    @InjectView(R.id.refreshImageView) ImageView mRefreshImageView;
    @InjectView(R.id.progressBar) ProgressBar mProgressBar;
    @InjectView(R.id.highTempValue) TextView mHighTemperature;
    @InjectView(R.id.lowTempValue) TextView mLowTemperature;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.inject(this);  //allows us to use a shortcut to link layout elements

        mProgressBar.setVisibility(View.INVISIBLE);

        final double latitude = 45.5233;
        final double longitude = -122.6762;

        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 = "21526f648c8ed449028d2533c39e7f4f";

        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()) {
                            mCurrentWeather = getCurrentDetails(jsonData);
                            runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    updateDisplay();
                                }

                            });

                            mDailyWeather = getDailyForecast(jsonData);
                            runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    updateDisplay();
                                }

                            });

                            Log.v(TAG, response.body().string());
                        } else {
                            alertUserAboutError();
                        }
                    } catch (IOException e) {
                        Log.e(TAG, "Exception caught: ", e);
                    }
                    catch (JSONException e){
                        Log.e(TAG, "Exception caught: ", e);
                    }

                }
            });
        }
    }

    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() {
        mTempuratureLabel.setText(mCurrentWeather.getTemperature() + "");
        mTimeLabel.setText("At " + mCurrentWeather.getFormattedTime() + " it will be");
        mHumidityValue.setText(mCurrentWeather.getHumidity() + "%");
        mPrecipValue.setText(mCurrentWeather.getPrecipChance() + "%");
        mWindValue.setText(mCurrentWeather.getWindSpeed()+ " MPH");
        mHighTemperature.setText(mDailyWeather[0].getHighTemperature() + "");
        mLowTemperature.setText(mDailyWeather[0].getLowTemperature() + "");
        mSummaryLabel.setText(mCurrentWeather.getSummary());

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

    private CurrentWeather 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");

        CurrentWeather currentWeather = new CurrentWeather();

        currentWeather.setHumidity(currently.getDouble("humidity"));
        currentWeather.setTime(currently.getLong("time"));
        currentWeather.setIcon(currently.getString("icon"));
        currentWeather.setPrecipChance(currently.getDouble("precipProbability"));;
        currentWeather.setSummary(currently.getString("summary"));
        currentWeather.setTemperature(currently.getDouble("temperature"));
        currentWeather.setTimeZone(timezone);
        currentWeather.setWindSpeed(currently.getDouble("windSpeed"));
        currentWeather.setWindBearing(currently.getInt("windBearing"));

        Log.d(TAG, currentWeather.getFormattedTime());
        Log.d(TAG, String.valueOf(currentWeather.getWindSpeed()) + " MPH");
        Log.d(TAG, String.valueOf(currentWeather.getWindBearing()) + " degrees");

        return currentWeather;
    }

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

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

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

          //removed from the for loop, as I think it is better placed here

        for (int i=0; i < data.length(); i++) {
            JSONObject jsonDay = data.getJSONObject(i);
            Day day = new Day();
            day.setTimeZone(timezone);
            day.setHighTemperature(jsonDay.getDouble("temperatureMax"));
            day.setLowTemperature(jsonDay.getDouble("temperatureMin"));

            days[i] = day;

            Log.d(TAG, String.valueOf(day.getHighTemperature() + " degrees F"));
            Log.d(TAG, String.valueOf(day.getLowTemperature() + " degrees F"));
        }
        return days;
    }

    private boolean isNetworkAvailable() {
        ConnectivityManager manager = (ConnectivityManager)
                getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo = manager.getActiveNetworkInfo();
        boolean isAvailable = false;
        if(networkInfo != null && networkInfo.isConnected()){
            isAvailable = true;
        }
        else{
            Toast.makeText(this, getString(R.string.network_unavailable_message),
                    Toast.LENGTH_LONG).show();
        }
        return isAvailable;
    }

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

Day.java

     package com.joshbgold.stormy;

     /**
      * Created by JoshG on 3/24/2015.
      */
     public class Day {
         private double mHighTemperature;
         private double mLowTemperature;
         private String mTimeZone;


         public double getHighTemperature() {
             return (int)Math.round(mHighTemperature);
         }

         public void setHighTemperature(double highTemperature) {
             mHighTemperature = highTemperature;
         }

         public double getLowTemperature() {
             return (int)Math.round(mLowTemperature);
         }

         public void setLowTemperature(double lowTemperature) {
             mLowTemperature = lowTemperature;
         }

         public String getTimeZone() {
             return mTimeZone;
         }

         public void setTimeZone(String timeZone) {
             mTimeZone = timeZone;
         }
    }
Josh Gold
Josh Gold
12,207 Points

I changed the method getDailyForecast to use and return the mDailyWeather variable. Even though this doesn't fix the problem, I think the is better.

    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[] mDailyWeather = new Day[data.length()];

        for (int i=0; i < data.length(); i++) {
            JSONObject jsonDay = data.getJSONObject(i);
            Day day = new Day();
            day.setTimeZone(timezone);
            day.setHighTemperature(jsonDay.getDouble("temperatureMax"));
            day.setLowTemperature(jsonDay.getDouble("temperatureMin"));

            mDailyWeather[i] = day;

            Log.d(TAG, String.valueOf(day.getHighTemperature() + " degrees F"));
            Log.d(TAG, String.valueOf(day.getLowTemperature() + " degrees F"));
        }
        return mDailyWeather;
    }

4 Answers

Josh Gold
Josh Gold
12,207 Points

Got the solution from user BarbiePylon via my post on Stack Overflow

You're calling onUpdateDisplay before mDailyWeather is initialized.

Remove the first call like so:

     mCurrentWeather = getCurrentDetails(jsonData);
     mDailyWeather = getDailyForecast(jsonData);
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                updateDisplay();
                            }
                        });
George Pirchalaishvili
George Pirchalaishvili
3,747 Points

Somehow I cannot see default constructor for you Day class. Can you check if you have it?

should be something like

public Day (){ }

even if it is empty

Josh Gold
Josh Gold
12,207 Points

Hello George, I have now added an empty constructor for the Day class.

Josh Gold
Josh Gold
12,207 Points

It didn't make things worse :-)

George Pirchalaishvili
George Pirchalaishvili
3,747 Points

In this row, try puting daily.getJSONArray("data"); instead of

    JSONArray data = forecast.getJSONArray("data");

I meant daily.getJSONArray("data"); instead

Josh Gold
Josh Gold
12,207 Points

After the substitution you suggested, things still compile fine, but I still have the same problem with mDailyWeather = null (and the other issue mDailyWeather[0] = Array reference expected).

George Pirchalaishvili
George Pirchalaishvili
3,747 Points

ok, what about these 2 logs:

        Log.d(TAG, String.valueOf(day.getHighTemperature() + " degrees F"));
        Log.d(TAG, String.valueOf(day.getLowTemperature() + " degrees F"));

what do they show to you in logcat?

Josh Gold
Josh Gold
12,207 Points

By the way, I appreciate your help as well George!

adriatik gashu
adriatik gashu
255 Points

hey did you have the answer for how to get and for the next 7 days or just for tomorrow.

Josh Gold
Josh Gold
12,207 Points

It's been awhile since I worked on this app, but the daily data block can return weather data for the next 7 days according to the API: https://developer.forecast.io/docs/v2#forecast_call

Scroll down to the section titled "Data Blocks."

Looking back at my code I am guessing that I could use the array index zero through six to access each day in the data block. Zero index means today, and one index means tomorrow, etc...

Examples:

    mHighTemperature.setText(mDailyWeather[0].getHighTemperature() + "");  //high temp for today
    mHighTemperature.setText(mDailyWeather[1].getHighTemperature() + "");  //high temp for tomorrow
    mHighTemperature.setText(mDailyWeather[2].getHighTemperature() + "");  //high temp for 2 days out
    mHighTemperature.setText(mDailyWeather[3].getHighTemperature() + "");  //high temp for 3 days out

    tomorrowHigh = mDailyWeather[1].getHighTemperature();