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 trialJonathan Grieve
Treehouse Moderator 91,253 Points[SOLVED] Stormy App - IllegalStateException on HourlyButtonClick method.
I'm almost there, and in fact, I've officially completed the course but I have one more problem to get over.
Once I've switched over the hourlyOnClick
method to bind to the JSON data the hourly Button triggers an IllegalStateException with the following stack trace. I've spent a great deal of time and research on this but I'm afraid I'm just not good at interpreting and debugging Stacktrace Errors.
https://github.com/jg-digital-media/stormy_list_tth
07-19 11:25:01.303 13973-13973/uk.co.jonniegrieve.stormy E/AndroidRuntime: FATAL EXCEPTION: main
Process: uk.co.jonniegrieve.stormy, PID: 13973
java.lang.IllegalStateException: Could not execute method for android:onClick
at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:389)
at android.view.View.performClick(View.java:5198)
at android.view.View$PerformClick.run(View.java:21147)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invoke(Native Method)
at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:384)
at android.view.View.performClick(View.java:5198)
at android.view.View$PerformClick.run(View.java:21147)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Caused by: java.lang.NullPointerException: storage == null
at java.util.Arrays$ArrayList.<init>(Arrays.java:38)
at java.util.Arrays.asList(Arrays.java:155)
at com.teamtreehouse.stormy.ui.MainActivity.hourlyOnClick(MainActivity.java:222)
at java.lang.reflect.Method.invoke(Native Method)
at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:384)
at android.view.View.performClick(View.java:5198)
at android.view.View$PerformClick.run(View.java:21147)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
--------- beginning of system
07-19 11:25:01.327 1228-1228/? E/EGL_emulation: tid 1228: eglCreateSyncKHR(1881): error 0x3004 (EGL_BAD_ATTRIBUTE)
No errors in the code... I really think it's something behind the scenes causing this. So near but yet so far. :)
package com.teamtreehouse.stormy.ui;
import android.content.Context;
import android.content.Intent;
import android.databinding.DataBindingUtil;
import android.graphics.drawable.Drawable;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.method.LinkMovementMethod;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.teamtreehouse.stormy.R;
import com.teamtreehouse.stormy.Weather.Current;
import com.teamtreehouse.stormy.Weather.Forecast;
import com.teamtreehouse.stormy.Weather.Hour;
import com.teamtreehouse.stormy.databinding.ActivityMainBinding;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class MainActivity extends AppCompatActivity {
public static final String TAG = MainActivity.class.getSimpleName();
private Forecast forecast;
private ImageView iconImageView;
double latitude = 37.8267;
double longitude = -122.4233;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getForecast(latitude, longitude);
Log.d(TAG, "Main UI code is running, hooray!");
}
private void getForecast(double latitude, double longitude) {
final ActivityMainBinding binding = DataBindingUtil
.setContentView(MainActivity.this, R.layout.activity_main);
iconImageView = findViewById(R.id.iconImageView);
// Setup Dark Sky Link
TextView darkSky = findViewById(R.id.darkSkyAttribution);
darkSky.setMovementMethod(LinkMovementMethod.getInstance());
String apiKey = "57eaf3aa961968bf65b0619680588073";
String forecastURL = "https://api.darksky.net/forecast/" + apiKey +
"/" + latitude + "," + longitude;
if (isNetworkAvailable()) {
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(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
try {
String jsonData = response.body().string();
Log.v(TAG, jsonData);
if (response.isSuccessful()) {
forecast = parseForecastData(jsonData);
Current current = forecast.getCurrent();
final Current displayWeather = new Current(
current.getLocationLabel(),
current.getIcon(),
current.getTime(),
current.getTemperature(),
current.getHumidity(),
current.getPrecipChance(),
current.getSummary(),
current.getTimeZone()
);
binding.setWeather(displayWeather);
runOnUiThread(new Runnable() {
@Override
public void run() {
Drawable drawable = getResources().getDrawable(displayWeather.getIconId());
iconImageView.setImageDrawable(drawable);
}
});
} else {
alertUserAboutError();
}
} catch (IOException e) {
Log.e(TAG, "IO Exception caught: ", e);
} catch (JSONException e) {
Log.e(TAG, "JSON Exception caught: ", e);
}
}
});
}
else {
Toast.makeText(this, R.string.network_unavailable_message,
Toast.LENGTH_LONG).show();
}
}
private Forecast parseForecastData(String jsonData) throws JSONException {
Forecast forecast = new Forecast();
forecast.setCurrent(getCurrentDetails(jsonData));
return forecast;
}
private Hour[] getHourlyForecast(String jsonData) throws JSONException {
JSONObject forecast = new JSONObject(jsonData);
String timezone = forecast.getString("timezone");
//get an array of JSON objects
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.setIcon(jsonHour.getString("icon"));
hour.setTemperature(jsonHour.getDouble("temperature"));
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();
// Parse weather data from currently object
current.setHumidity(currently.getDouble("humidity"));
current.setTime(currently.getLong("time"));
current.setIcon(currently.getString("icon"));
current.setLocationLabel("Alcatraz Island, CA");
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");
}
public void refreshOnClick(View view) {
getForecast(latitude, longitude);
Toast.makeText(this, "Refreshing data", Toast.LENGTH_LONG).show();
}
public void hourlyOnClick(View view) {
List<Hour> hours = Arrays.asList(forecast.getHourlyForecast());
Intent intent = new Intent(this, HourlyForecastActivity.class);
intent.putExtra("HourlyList", (Serializable) hours);
startActivity(intent);
}
}
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name = "weather"
type = "com.teamtreehouse.stormy.Weather.Current"/>
</data>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/appBackground"
tools:context="com.teamtreehouse.stormy.ui.MainActivity">
<TextView
android:id="@+id/temperatureView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="@{String.valueOf(Math.round(weather.temperature)), default = `100`}"
android:textColor="@android:color/white"
android:textSize="150sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<ImageView
android:id="@+id/degreeImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="35dp"
app:layout_constraintStart_toEndOf="@+id/temperatureView"
app:layout_constraintTop_toTopOf="@+id/temperatureView"
app:srcCompat="@drawable/degree"/>
<TextView
android:id="@+id/timeValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:text="@{`At ` + String.valueOf(weather.formattedTime) + ` it will be`, default = `At 5:00 PM it will be`}"
android:textColor="@color/half_white"
android:textSize="18sp"
app:layout_constraintBottom_toTopOf="@+id/temperatureView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
<TextView
android:id="@+id/locationValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="24dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:text="Alcatraz Island, CA"
android:textColor="@android:color/white"
android:textSize="24sp"
app:layout_constraintBottom_toTopOf="@+id/timeValue"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
<ImageView
android:id="@+id/iconImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginStart="32dp"
app:layout_constraintBottom_toBottomOf="@+id/locationValue"
app:layout_constraintStart_toStartOf="parent"
app:srcCompat="@drawable/cloudy_night"/>
<android.support.constraint.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.33"/>
<android.support.constraint.Guideline
android:id="@+id/guideline2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.66"/>
<TextView
android:id="@+id/humidityLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginTop="16dp"
android:text="HUMIDITY"
android:textColor="@color/half_white"
app:layout_constraintEnd_toStartOf="@+id/guideline"
app:layout_constraintStart_toStartOf="@+id/guideline"
app:layout_constraintTop_toBottomOf="@+id/temperatureView"/>
<TextView
android:id="@+id/humidityValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:text="@{String.valueOf(weather.humidity), default=`0.88`}"
android:textColor="@android:color/white"
android:textSize="24sp"
app:layout_constraintEnd_toEndOf="@+id/humidityLabel"
app:layout_constraintStart_toStartOf="@+id/humidityLabel"
app:layout_constraintTop_toBottomOf="@+id/humidityLabel"/>
<TextView
android:id="@+id/precipLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginTop="15dp"
android:text="RAIN/SNOW?"
android:textColor="@color/half_white"
app:layout_constraintEnd_toStartOf="@+id/guideline2"
app:layout_constraintStart_toStartOf="@+id/guideline2"
app:layout_constraintTop_toBottomOf="@+id/temperatureView"/>
<TextView
android:id="@+id/precipValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:text="@{String.valueOf(Math.round(weather.precipChance * 100)) + ` %`, default = `50 %`}"
android:textColor="@android:color/white"
android:textSize="24sp"
app:layout_constraintEnd_toEndOf="@+id/precipLabel"
app:layout_constraintStart_toStartOf="@+id/precipLabel"
app:layout_constraintTop_toBottomOf="@+id/precipLabel"/>
<TextView
android:id="@+id/summaryValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="@{weather.summary, default = `Stormy with a chance of meatballs`}"
android:textColor="@android:color/white"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/precipValue"/>
<TextView
android:id="@+id/darkSkyAttribution"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:text="@string/dark_sky_message"
android:textColor="@color/half_white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
<ImageView
android:id="@+id/refreshImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:onClick="refreshOnClick"
app:layout_constraintBottom_toTopOf="@+id/locationValue"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/refresh"/>
<Button
android:id="@+id/hourlyButton"
android:layout_width="wrap_content"
android:layout_height="30dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:background="#40ffffff"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:textColor="@android:color/white"
android:onClick="hourlyOnClick"
android:text="Hourly Forecast"
app:layout_constraintBottom_toTopOf="@+id/darkSkyAttribution"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/summaryValue"/>
</android.support.constraint.ConstraintLayout>
</layout>
1 Answer
Jonathan Grieve
Treehouse Moderator 91,253 PointsFound out the issue in the end. I'm still not good at reading Stacktraces but here's the StackOverflow threadat pointed me in the right direction. I wasn't returning the method properly because I wasn't actually parsing the Data in JSON format with the parse method.
private Forecast parseForecastData(String jsonData) throws JSONException {
Forecast forecast = new Forecast();
forecast.setCurrent(getCurrentDetails(jsonData));
forecast.setHourlyForecast(getHourlyForecast(jsonData));
return forecast;
}