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 trialEgo Team
17,902 PointsMy code won't parse the json timezone string. keeps catching a json exception
Here is the error :(
12-06 22:31:27.845 25528-25528/lucasSenechal.stormy E/Main_Activity﹕ Main_Activity is running! 12-06 22:31:28.655 25528-25543/lucasSenechal.stormy E/Main_Activity﹕ com.squareup.okhttp.internal.http.RealResponseBody@42b247d0 12-06 22:31:28.665 25528-25543/lucasSenechal.stormy E/Main_Activity﹕ exception caught: org.json.JSONException: Value com.squareup.okhttp.internal.http.RealResponseBody@42b247d0 of type java.lang.String cannot be converted to JSONObject at org.json.JSON.typeMismatch(JSON.java:111) at org.json.JSONObject.<init>(JSONObject.java:159) at org.json.JSONObject.<init>(JSONObject.java:172) at lucasSenechal.stormy.Main_Activity.getCurrentDetails(Main_Activity.java:80) at lucasSenechal.stormy.Main_Activity.access$100(Main_Activity.java:26) at lucasSenechal.stormy.Main_Activity$1.onResponse(Main_Activity.java:63) at com.squareup.okhttp.Call$AsyncCall.execute(Call.java:168) at com.squareup.okhttp.internal.NamedRunnable.run(NamedRunnable.java:33) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) at java.lang.Thread.run(Thread.java:841)
Here is my code
public class Main_Activity extends Activity {
public static final String TAG = Main_Activity.class.getSimpleName();
private CurrentWeather mCurrentWeather;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_);
double latitude = 37.8267;
double longitude = -122.423;
String apiKey = "26351d54df6d07aff2086c471da36d36";
String forecastURL = "https://api.forecast.io/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(Request request, IOException e) {
}
@Override
public void onResponse(Response response) throws IOException {
String jsonData = response.body().toString();
Log.e(TAG, jsonData);
try {
if (response.isSuccessful()) {
mCurrentWeather = getCurrentDetails(jsonData);
} else {
alertUserAboutError();
}
}
catch (JSONException e){
Log.e(TAG, "exception caught: ", e);
}
}
});
} else {
Toast.makeText(this, getString(R.string.network_isUnavailable), Toast.LENGTH_LONG).show();
}
Log.e(TAG, "Main_Activity is running!");
}
private CurrentWeather getCurrentDetails(String jsonData) throws JSONException {
JSONObject forecast = new JSONObject(jsonData);
String timezone = forecast.getString("timezone");
Log.i(TAG, "From json: " + timezone);
return new CurrentWeather();
}
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 mDialog = new AlertDialogFragment();
mDialog.show(getFragmentManager(), "error_dialog");
}
}
Please help :(
1 Answer
Gavin Ralston
28,770 PointsSo we know getCurrentDetails() is doing something to throw an error our way, because we read the stack trace from bottom to top in order to visualize how everything's being called and where we break down. So starting from "Thread.run" we work our way "up"
Let's look at when it gets interesting, or familiar to us based on the code we wrote:
E/Main_Activity﹕ exception caught: org.json.JSONException: Value
com.squareup.okhttp.internal.http.RealResponseBody@42b247d0
of type java.lang.String cannot be converted to
JSONObject at org.json.JSON.typeMismatch(JSON.java:111)
at org.json.JSONObject.(JSONObject.java:159)
at org.json.JSONObject.(JSONObject.java:172)
at lucasSenechal.stormy.Main_Activity.getCurrentDetails(Main_Activity.java:80)
at lucasSenechal.stormy.Main_Activity.access$100(Main_Activity.java:26)
at lucasSenechal.stormy.Main_Activity$1.onResponse(Main_Activity.java:63)
at com.squareup.okhttp.Call$AsyncCall.execute(Call.java:168) at
...blah...blah....blah...
Thread.run
So we can see that the asynchoronous call got made, and the onResponse callback got called and came back alright, so the getCurrentDetails() method was called....and that's exactly where it threw a fit about the "String cannot be converted to JSONObject" bit.
So let's see what getCurrentDetails() is working on...
@Override
public void onResponse(Response response) throws IOException {
String jsonData = response.body().toString();
Log.e(TAG, jsonData);
try {
if (response.isSuccessful()) {
mCurrentWeather = getCurrentDetails(jsonData);
} else {
alertUserAboutError();
}
}
catch (JSONException e){
Log.e(TAG, "exception caught: ", e);
}
}
});
Well, looks like you're creating a String for your jsonData variable.
But if you recall (and it took me a moment!) you're not supposed to call .toString() on the response body, but rather you're supposed to use the string() method from the okhttp.Response.ResponseBody in order to give you back a string of the body of the response.
If you call toString(), there's a good chance it'll provide you with either the java default (which is just a plaintext representation of the address in memory) or maybe a human-readable representation of the object, like "Hey, this is a Response Body" but definitely not the JSON you're looking for.
You can check out the OkHttp documentation here and click through Response, then ResponseBody, and then find the string() method to see a kind of arcane, but useful description.
The tl;dr is below :)
Somewhere around line 80 you're getting an error generated. Remember that the getCurrentDetails method THROWS an error, so it could be complaining about the spot where you called it -- passing in bad information that it can't parse or format. It turns out that's exactly what the problem is: Use string() from the OkHttp.Response.ResponseBody object, not the java toString() method.
public void onResponse(Response response) throws IOException {
String jsonData = response.body().string(); // make your change here
try {
if (response.isSuccessful()) {
mCurrentWeather = getCurrentDetails(jsonData); // now this will be passed the right data!
} else {
alertUserAboutError(); // and this won't get called.
}
Sang Tran
6,918 PointsSang Tran
6,918 PointsThanks for this