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!
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

Josh Gold
12,206 PointsAttempting 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;
}
}
4 Answers

Josh Gold
12,206 PointsGot 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
3,747 PointsSomehow 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
12,206 PointsHello George, I have now added an empty constructor for the Day class.

Josh Gold
12,206 PointsIt didn't make things worse :-)

George Pirchalaishvili
3,747 PointsIn this row, try puting daily.getJSONArray("data"); instead of
JSONArray data = forecast.getJSONArray("data");
I meant daily.getJSONArray("data"); instead

Josh Gold
12,206 PointsAfter 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
3,747 Pointsok, 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
12,206 PointsBy the way, I appreciate your help as well George!

adriatik gashu
255 Pointshey did you have the answer for how to get and for the next 7 days or just for tomorrow.

Josh Gold
12,206 PointsIt'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();
Josh Gold
12,206 PointsJosh Gold
12,206 PointsI changed the method getDailyForecast to use and return the mDailyWeather variable. Even though this doesn't fix the problem, I think the is better.