Related
I am getting some info from the server and the for used in onPostExecute was supposed to store the data into 2 different arrays. The server's response it's alright, it gets to the app, it is recognized as a JSON object, but when it comes to transforming it to a JSONArray to get the elements it just gets over that part of the code, as it wouldn't be written. So, after the JSONArray departamenteArray = obj.getJSONArray("departamente"); line, it just goes over the rest of it without making any changes.
.java code:
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
//hiding the progressbar after completion
try {
//converting response to json object
JSONObject obj = new JSONObject(s);
//if no error in response
if (!obj.getBoolean("error")) {
JSONArray departamenteArray = obj.getJSONArray("departamente");
for (int i = 0; i < departamenteArray.length(); i++) {
JSONObject dep = departamenteArray.getJSONObject(i);
// Verificare daca s-au primit probleme trimise de server
if (!dep.isNull("Departament")) {
String departament = SchimbareDiactritice(dep.getString("Departament")).replace("&","");
String id_departament= dep.getString("id_departament");
id_departamente.add(id_departament);
departamente.add(departament);
}
}
} else {
Toast.makeText(getApplicationContext(), "Some error occurred", Toast.LENGTH_SHORT).show();
}
} catch (JSONException e) {
e.printStackTrace();
}
layout_validare.setVisibility(GONE);
linearLayout_obs_redirectionare.setVisibility(View.VISIBLE);
}
JSON response from the server :
{
"error": false,
"message": "Alerte reimprospatate",
"departamente": [{
"Departament": "Parcări",
"id_departament": 2
}, {
"Departament": "Trafic rutier și iluminat public",
"id_departament": 3
}, {
"Departament": "Salubritate și vandalism",
"id_departament": 4
}, {
"Departament": "Altele",
"id_departament": 5
}]
}
.php code on the server side:
if($stmt->num_rows > 0){
$stmt->bind_result($departament, $id_departament);
while($stmt->fetch()) {
$departamente[] = array (
"Departament"=>$departament,
"id_departament"=>$id_departament
);
$response['error'] = false;
$response['message'] = 'Alerte reimprospatate';
$response['departamente']= $departamente;
It seems that after a restart of the Android Studio it works. It must have been only a bug. The code shown above it's working properly.
W/O using Hashmap or GSON. This is my first time parsing a nested array. I know how to parse a single array and JSON objects. I've looked at several threads on here and I'm basing my code on this one:
How to parse this nested JSON array in android
I'm parsing the following JSON data(pasted from Postman) from the following url. JSON structure pasted below.
https://api.tfl.gov.uk/Line/victoria/Route/Sequence/inbound?serviceTypes=Regular,Night
I want to return a list of 16 subway stations in sequential order; return "id":940GDCOELW" or "naptanId:940DFDDKLJ09" and "name":"Warren Street Underground Station" for all the stations. They are stored in both "stations"(non-sequential) and "stopPointSequences" arrays and also in "orderedLineRoutes". I started parsing "stopPointSequences", but I'm not sure how to add the data to the ArrayList. Error indicated above the code. Or, would it be easier to parse "orderedLineRoutes"? But is it possible to parse it by matching the name to the id? I'm not sure if every "name" is included in the array. The first part of "stopPointSequence" array pasted below. Thank you in advance.
{
"$type": "Tfl.Api.Presentation.Entities.RouteSequence, Tfl.Api.Presentation.Entities",
"lineId": "victoria",
"lineName": "Victoria",
"direction": "inbound",
"isOutboundOnly": false,
"mode": "tube",
"lineStrings":[..];
"stations":[..];
"stopPointSequences":[
{
"$type": "Tfl.Api.Presentation.Entities.StopPointSequence, Tfl.Api.Presentation.Entities",
"lineId": "victoria",
"lineName": "Victoria",
"direction": "inbound",
"branchId": 0,
"nextBranchIds": [],
"prevBranchIds": [],
"stopPoint": [
{
"$type": "Tfl.Api.Presentation.Entities.MatchedStop, Tfl.Api.Presentation.Entities",
"parentId": "HUBWHC",
"stationId": "940GZZLUWWL",
"icsId": "1000249",
"topMostParentId": "HUBWHC",
"modes": [
"tube"
],
"stopType": "NaptanMetroStation",
"zone": "3",
"hasDisruption": true,
"lines": [{..}],
"status": true,
"id": "940GZZLUWWL",
"name": "Walthamstow Central Underground Station",
"lat": 51.582965,
"lon": -0.019885
},
],
"orderedLineRoutes": [
{
"$type": "Tfl.Api.Presentation.Entities.OrderedRoute, Tfl.Api.Presentation.Entities",
"name": "Walthamstow Central ↔ Brixton ",
"naptanIds": [
"940GZZLUWWL",
"940GZZLUBLR",
"940GZZLUTMH",
"940GZZLUSVS",
"940GZZLUFPK",
"940GZZLUHAI",
"940GZZLUKSX",
"940GZZLUEUS",
"940GZZLUWRR",
"940GZZLUOXC",
"940GZZLUGPK",
"940GZZLUVIC",
"940GZZLUPCO",
"940GZZLUVXL",
"940GZZLUSKW",
"940GZZLUBXN"
],
"serviceType": "Night"
},
{
"$type": "Tfl.Api.Presentation.Entities.OrderedRoute, Tfl.Api.Presentation.Entities",
"name": "Walthamstow Central ↔ Brixton ",
"naptanIds": [
"940GZZLUWWL",
"940GZZLUBLR",
"940GZZLUTMH",
"940GZZLUSVS",
"940GZZLUFPK",
"940GZZLUHAI",
"940GZZLUKSX",
"940GZZLUEUS",
"940GZZLUWRR",
"940GZZLUOXC",
"940GZZLUGPK",
"940GZZLUVIC",
"940GZZLUPCO",
"940GZZLUVXL",
"940GZZLUSKW",
"940GZZLUBXN"
],
"serviceType": "Regular" }]
}},
JSONUTILS class:
public static ArrayList<Stations> extractFeatureFromStationJson(String stationJSON) {
// If the JSON string is empty or null, then return early.
if (TextUtils.isEmpty(stationJSON)) {
return null;
}
ArrayList<Stations> stations = new ArrayList<>();
try {
// Create a JSONObject from the JSON response string
JSONObject baseJsonResponse = new JSONObject(stationJSON);
JSONArray stopPointSequenceArrayList = baseJsonResponse.getJSONArray("stopPointSequences");
if (stopPointSequenceArrayList != null) {
for (int i = 0; i < stopPointSequenceArrayList.length(); i++) {
JSONObject elem = stopPointSequenceArrayList.getJSONObject(i);
if (elem != null) {
JSONArray stopPointArrayList = elem.getJSONArray("stopPoint");
if (stopPointArrayList != null) {
for (int j = 0; j < stopPointArrayList.length(); j++) ;
JSONObject innerElem = stopPointArrayList.getJSONObject(i);
if (innerElem != null) {
String idStation = "";
if (innerElem.has("id")) {
idStation = innerElem.optString(KEY_STATION_ID);
}
String nameStation = "";
if (innerElem.has("name")) {
nameStation = innerElem.optString(KEY_STATION_NAME);
}
//Error stopPointSequenceArrayList.add(stopPointArrayList);
}
}
}
}
}
//Error
Stations station = new Stations(idStation, nameStation);
stations.add(station);
} catch (JSONException e) {
// If an error is thrown when executing any of the above statements in the "try" block,
// catch the exception here, so the app doesn't crash. Print a log message
// with the message from the exception.
Log.e("QueryUtils", "Problem parsing stations JSON results", e);
}
// Return the list of stations
return stations;
}
There is couple errors inside your code so this should work now. You can now extract id and name values:
try {
ArrayList<Stations> stations = new ArrayList<>();
// Create a JSONObject from the JSON response string
JSONObject baseJsonResponse = new JSONObject(stationJSON);
JSONArray stopPointSequenceArrayList = baseJsonResponse.getJSONArray("stopPointSequences");
if (stopPointSequenceArrayList != null) {
for (int i = 0; i < stopPointSequenceArrayList.length(); i++) {
JSONObject elem = stopPointSequenceArrayList.getJSONObject(i);
if (elem != null) {
JSONArray stopPointArrayList = elem.getJSONArray("stopPoint");
if (stopPointArrayList != null) {
for (int j = 0; j < stopPointArrayList.length(); j++) {
JSONObject innerElem = stopPointArrayList.getJSONObject(i);
if (innerElem != null) {
String id = innerElem.getString("id");
String name = innerElem.getString("name");
Log.d("Element", name);
Log.d("Element", id);
Stations station = new Stations(id, name);
stations.add(station);
}
}
}
}
}
return stations;
}
return null; //something went wrong
} catch (Exception e) {
// If an error is thrown when executing any of the above statements in the "try" block,
// catch the exception here, so the app doesn't crash. Print a log message
// with the message from the exception.
Log.e("QueryUtils", "Problem parsing stations JSON results", e);
return null; // something went wrong exception is thrown
}
I have been attempting to retrieve information from an online JSON Source using a URL. I initially got the information parsed to a TextView in Android, however I got ALL Information from the JSON. Below is a screenshot of what I am referring to.
Text View Showing All Data In Json
Essentially, What I want is to just show the Location, so in the above example, Oslo, in Norway in one Textview, then in another show the Current Moon Phase for that location, so - using the above example again, Waxing Crescent.
This is the JSON I am using.
{
"version": 2,
"locations": [{
"id": "187",
"geo": {
"name": "Oslo",
"country": {
"id": "no",
"name": "Norway"
},
"latitude": 59.913,
"longitude": 10.740
},
"astronomy": {
"objects": [{
"name": "moon",
"days": [{
"date": "2018-09-13",
"events": [],
"moonphase": "waxingcrescent"
}]
}]
}
}]
}
To parse the JSON to the Textview showing all the data I used the following.
JSONObject jo = new JSONObject(data);
JSONArray locations = jo.getJSONArray("locations");
for (int i = 0; i < locations.length(); ++i) {
JSONObject loc = locations.getJSONObject(0);
JSONObject geo = loc.getJSONObject("geo");
JSONObject country = geo.getJSONObject("country");
JSONObject astronomy = loc.getJSONObject("astronomy");
JSONObject objects = astronomy.getJSONArray("objects").getJSONObject(0);
JSONObject day = objects.getJSONArray("days").getJSONObject(0);
StringBuilder result = new StringBuilder();
String singleParsed = "Moon: "+ astronomy.getString("moonphase");
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
#RequiresApi(api = Build.VERSION_CODES.CUPCAKE)
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
MainActivity.fetcheddata.setText(this.data);
}
NOTE: A String is created in the For Loop, Called "Single Parsed", This is what I want to put on the screen, however - once I call that variable, nothing shows on the screen. It only shows when using:
MainActivity.fetcheddata.setText(this.data);
But Not with the following, I do actually receive an error saying "Cannot Resolve Symbol, singleParsed as well.
MainActivity.fetcheddata.setText(this.singleParsed);
After some research and previous questions on Stack, I believe GSON is the way to go to do what I wish, however I have no idea where to start, or how to do the task using GSON.
All help is appreciated.
JSON Information from URL through GSON
Simple answer - Look at using Retrofit, and find a tutorial on it, as well as Gson
However
You don't need Gson to fix your problem, and I suggest fixing the problem at hand rather than going down an unnecessary path.
First, singleParsed is a local variable within a loop. Therefore, this.singleParsed doesn't exist. Or if it does, you never set it.
Secondly, let's assume you only have one location, so you don't need a loop. Similar to how you accessed the other JSON arrays, just get the first array item.
Finally, you'll need to understand how AsyncTask works, but my general recommended solution is at How to get the result of OnPostExecute() to main activity because AsyncTask is a separate class?
But, for this purpose, here is a simple example with AsyncTask<String, Void, String>
// protected String doInBackground(String... url) { // I assume you have this ??
// String data = parseJsonFrom(url[0]);
String singleParsed = "(none)";
try {
JSONObject jo = new JSONObject(data);
JSONObject firstLocationAstronomy = jo
.getJSONArray("locations").getJSONObject(0)
.getJSONObject("astronomy");
JSONObject firstDay = firstLocationAstronomy
.getJSONArray("objects").getJSONObject(0)
.getJSONArray("days").getJSONObject(0);
singleParsed = firstDay.getString("moonphase");
} catch (Exception e) { // TODO: catch a JSONParseException
}
return singleParsed; // This is returned to onPostExecute, don't store a variable elsewhere
}
Then in the MainActivity, wherever you make this task, and set the text
new MoonPhaseTask() {
#Override
protected void onPostExecute(String moonPhase) {
MainActivity.this.textView.setText("Phase: " + moonPhase);
}
}.execute("some url");
What I want is to just show the Location, so in the above example, Oslo, in Norway in one Textview, then in another show the Current Moon Phase for that location
You can change the AsyncTask to return you the entire JSONObject to the onPostExecute, and parse the JSON there if you really wanted. Just the networking pieces need to be off the UI thread... parsing is not computationally expensive.
History callback is shown below,I need to parse Object response (message) which response is given below for reference.Object message - params which produce nested array without any keyword and nested object with keyword as message.
pubnub.history(request_id, true, 100, new Callback() {
#Override
public void successCallback(String channel, Object message) {
super.successCallback(channel, message);
Log.e(TAG, "successCallback: History Messages" + message);
}
#Override
public void errorCallback(String channel, PubnubError error) {
super.errorCallback(channel, error);
Log.e(TAG, "successCallback: History Messages error" + error);
}
});
Here is my Object response message.
Response:-
[ //array 1
[ // array 2
{ //obj 1
"message":{
"message":"Hai",
"timestamp":1507105493379,
"type":"SENT",
"userId":137
},
"timetoken":15071054937865507
},
{ //object 2
"message":{
"message":"How are you ?",
"timestamp":1507105503320,
"type":"SENT",
"userId":137
},
"timetoken":15071055037143632
},
{ //object 3
"message":{
"message":"Fyn",
"timestamp":1507105505628,
"type":"SENT",
"userId":137
},
"timetoken":15071055060355900
}
], //array 1 end
15071054937865507,
15071055060355900
]
//array 2 end
How to parse this response.
You can parse your JSON using below code
Call parseJson() inside your successCallback method and pass message.toString() to parse method like this:
public void successCallback(String channel, Object message) {
super.successCallback(channel, message);
Log.e(TAG, "successCallback: History Messages" + message);
parseJson(message.toString());
}
JsonParse method:
private void parseJson(String jsonStr) {
try{
JSONArray jsonArray = new JSONArray(jsonStr);
JSONArray innerJsonArray = jsonArray.getJSONArray(0);
for(int i = 0; i < innerJsonArray.length(); i++) {
JSONObject jsonObject = innerJsonArray.getJSONObject(i);
JSONObject jsonObjectMessage = jsonObject.getJSONObject("message");
String msg = jsonObjectMessage.getString("message");
//TODO you can get all other fields
}
}catch (JSONException e){
e.printStackTrace();
}
}
first of all this is not a valid JSON, maybe this is way you are having trouble parsing it.
when you'll get a valid json (and you can check if it is a valid json in here https://jsonlint.com/) , you will need to first cast it from a string as a json object and then get every child and every child of a child ans so on until u get the whole object.
you should use some json parser like this one:http://json.parser.online.fr/ to help you understand what object is a child of what
good luck
I'm having trouble with my app that is supposed to take in user text input and search Google Books API. Thus far I am able to successfully take in user input, add it to the query string and start an AsyncTask, start HttpRequest, take the inputStream and build a string from it, create an array of items from the string, and then use a custom adapter to display that book listing on the screen for the user.
The trouble I'm having is that when the code runs (regardless of what the user inputs, be it food, greek, android, whatever) I only get one response showing up on the screen. I can't figure out why it's only showing up one book. The API query string specifies 10 (I've also used 2, 4, & 7) as the max result but I've thus far only gotten 1 list. After checking with the debugger I've narrowed it down to either the Stringbuilder stops after a certain length of input or my arraylist isn't creating other indices for the rest of the JSONObjects.
Below is the Book Activity code:
package com.ovidioreyna.android.googlebooksapiapp;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.util.Log;
import android.widget.ListView;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.ArrayList;
import static com.ovidioreyna.android.googlebooksapiapp.MainActivity.LOG_TAG;
public class BooksActivity extends AppCompatActivity {
//Creates blank global string which will be used the search parameters in this class
public String gglBookSearch = "https://www.googleapis.com/books/v1/volumes?q=";
//After the user enters what they want to search for we pass that in from the main activity
//and add it to our global variable here. We then add some modifiers so that we can control
//the amount of info being return. This will later be changed to 10 once the app is functioning
Context context = this;
String jsonResponse = "";
ListView booksListView;
BookAdapter adapter;
//inflates the book_layout.xml so we can see the book info
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.book_list);
//passes the user input to this activity
Bundle extras = getIntent().getExtras();
if (extras != null) {
String textSearchUpdate = extras.getString("EDITTEXTUPDATE");
//takes user input and appends it to the initial Google Books API Query
updateApiSearch(textSearchUpdate);
}
//creates an instance of BooksAsynTask and executes it
BooksAsyncTask task = new BooksAsyncTask();
task.execute();
}
//Sets the appropriate info to the appropriate textviews
private void updateUi(ArrayList<Books> books) {
//creates an instance of the book list
booksListView = (ListView) findViewById(R.id.book_list);
//creates an instance of the book adapter
adapter = new BookAdapter(context, new ArrayList<Books>());
//sets the adapter to the listview.xml
booksListView.setAdapter(adapter);
//in case user initiates multiple searches then we need to clear the adapter to start with
//clean adapter for the new search
adapter.clear();
adapter.addAll(books);
adapter.notifyDataSetChanged();
}
private class BooksAsyncTask extends AsyncTask<URL, Void, ArrayList<Books>> {
#Override
protected ArrayList<Books> doInBackground(URL... urls) {
//creates a new url object from the #gglBookSearch query
URL url = createUrl(gglBookSearch);
try {
//creates a string that will hold the raw data for the jsonarray
jsonResponse = makeHttpRequest(url);
Log.i(LOG_TAG, "JSON Results: " + jsonResponse);
} catch (IOException e) {
Log.e(LOG_TAG, "Error with make request", e);
}
//takes the raw string data and extracts it into an array
return extractBooks(jsonResponse);
}
#Override
protected void onPostExecute(ArrayList<Books> books) {
//checks to make sure that the arraylist books is not empty
if (books == null) {
return;
}
//if all goes well and books is populated then it displays that info
updateUi(books);
}
private URL createUrl(String stringUrl) {
//creates a new url object from the string passed in
URL url = null;
try {
url = new URL(stringUrl);
} catch (MalformedURLException exception) {
Log.e(LOG_TAG, "Error with creating URL", exception);
}
return url;
}
public ArrayList<Books> extractBooks(String jsonResponse) {
//craetes a new Arraylist that will hold all the json data
ArrayList<Books> books = new ArrayList<>();
//checks to see that the string passed in is not empty
if (TextUtils.isEmpty(jsonResponse)) {
return null;
}
try {
//creates a jsonObject to hold the data. Then delves into the Array items
JSONObject baseJsonResponse = new JSONObject(jsonResponse);
JSONArray itemsArray = baseJsonResponse.getJSONArray("items");
Log.i(LOG_TAG, "Length of books array: " + itemsArray.length());
//create empty local variables in case the JSON objects are null
String bookTitle = "";
String bookSubtitle = "";
String author = "";
String publishedDate = "";
for (int i = 0; i < itemsArray.length(); i++) {
//checks to see that the Array isn't empty
if (itemsArray.length() > 0) {
JSONObject firstItem = itemsArray.getJSONObject(i);
JSONObject volumeInfo = firstItem.getJSONObject("volumeInfo");
//checks to see if object is null, if not then executes code
if (!volumeInfo.isNull("title")) {
bookTitle = volumeInfo.getString("title");
}
//checks to see if object is null, if not then executes code
if (!volumeInfo.isNull("subtitle")) {
bookSubtitle = volumeInfo.getString("subtitle");
}
//creates an jsonArray object from the authors array
JSONArray authorArray = volumeInfo.getJSONArray("authors");
if (!authorArray.isNull(i)) {
if (authorArray.length() == 1) {
author = authorArray.getString(i);
} else {
for (int k = 0; k < authorArray.length(); k++) {
//checks to see if object is null, if not then executes code
if (!authorArray.isNull(k)) {
author = authorArray.getString(k) + ",";
}
}
}
}
//checks to see if object is null, if not then executes code
if (!volumeInfo.isNull("publishedDate"))
publishedDate = volumeInfo.getString("publishedDate");
//create a new instance of the Books class
Books book = new Books(bookTitle, bookSubtitle, author, publishedDate);
books.add(book);
}
return books;
}
} catch (JSONException e) {
Log.e(LOG_TAG, "Problem with parsing the books JSON results", e);
}
//if there is an error in the code above it returns null
return null;
}
private String makeHttpRequest(URL url) throws IOException {
//checks to see that the url object passed in is not empty. If empty then returns an
//empty string
if (url == null) {
return jsonResponse = "";
}
//creates two empty objects
HttpURLConnection urlConnection = null;
InputStream inputStream = null;
//this is where we try to establish a connection and if successful take the input info
//and convert it into a usable form
try {
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.setReadTimeout(10000 /* milliseconds */);
urlConnection.setConnectTimeout(15000 /* milliseconds */);
urlConnection.connect();
if (urlConnection.getResponseCode() == 200) {
//if we get a success code from the server we proceed to convert the bits and
//bytes into a usuable form and ultimately convert it into a usable string.
inputStream = urlConnection.getInputStream();
jsonResponse = readFromStream(inputStream);
} else {
//if we don't get a success code from the server we log it.
Log.e(LOG_TAG, "Error Response Code: " + urlConnection.getResponseCode());
}
} catch (IOException e) {
Log.e(LOG_TAG, "Problem With Connection: ", e);
} finally {
//regardless if we are successful gettting an inputstream or not we disconnect and
//close the inputstream
if (urlConnection != null) {
urlConnection.disconnect();
}
if (inputStream != null) {
inputStream.close();
}
}
//returns the string #jsonResponse whether it's empty or has information
return jsonResponse;
}
//uses StringBuilder to take the raw bits and make a legible string from it
private String readFromStream(InputStream inputStream) throws IOException {
StringBuilder output = new StringBuilder();
if (inputStream != null) {
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, Charset.forName("UTF-8"));
BufferedReader reader = new BufferedReader(inputStreamReader);
String line = reader.readLine();
while (line != null) {
output.append(line);
line = reader.readLine();
}
}
//once the entire input stream has been built we output it to a string
return output.toString();
}
}
//takes the input text from the user and concatonates it to the query as well as adding a limit
//of 10 books at a time
public void updateApiSearch(String updatedEditText) {
gglBookSearch += updatedEditText;
gglBookSearch += "&maxResults=10";
}
}
Here is the link to the entire repo if anyone would like to have the entire code to mess with:
https://github.com/ovidioreyna/GoogleBooksAPIApp
Thanks in advance for your help
UPDATE:
So I created a log event to show the JSON results after jsonResponse = makeHttpRequest(url); and the logs showed this:
10-09 20:50:36.846 32119-32463/com.ovidioreyna.android.googlebooksapiapp I/MainActivity: JSON Results: { "kind": "books#volumes", "totalItems": 1431, "items": [ { "kind": "books#volume", "id": "vdXmDAAAQBAJ", "etag": "pSHAL8HBKSs", "selfLink": "https://www.googleapis.com/books/v1/volumes/vdXmDAAAQBAJ", "volumeInfo": { "title": "Molly on the Range", "subtitle": "Recipes and Stories from an Unlikely Life on a Farm", "authors": [ "Molly Yeh" ], "publisher": "Rodale", "publishedDate": "2016-10-04", "description": "In 2013, food blogger and classical musician Molly Yeh left Brooklyn to live on a farm on the North Dakota-Minnesota border, where her fiancé was a fifth-generation Norwegian-American sugar beet farmer. Like her award-winning blog My Name is Yeh, Molly on the Range chronicles her life through photos, more than 120 new recipes, and hilarious stories from life in the city and on the farm. Molly’s story begins in the suburbs of Chicago in the 90s, when things like Lunchables and Dunkaroos were the objects of her affection; continues into her New York years, when Sunday mornings meant hangovers and bagels; and ends in her beloved new home, where she’s currently trying to master the art of the hotdish. Celebrating Molly's Jewish/Chinese background with recipes for Asian Scotch Eggs and Scallion Pancake Challah Bread and her new hometown Scandinavian recipes for Cardamom Vanilla Cake and Marzipan Mandel Bread, Molly on the Range will delight everyone, from longtime readers to those discovering her glorious writing and recipes for the first time.", "industryIdentifiers": [ { "type": "ISBN_13", "identifier": "9781623366957" }, { "type": "ISBN_10", "identifier": "162336695X" } ], "readingModes": { "text": false, "image": false }, "pageCount": 304, "printType": "BOOK", "categories": [ "Cooking" ], "maturityRating": "NOT_MATURE", "allowAnonLogging": false, "contentVersion": "1.1.1.0.preview.0", "imageLinks": { "smallThumbnail": "http://books.google.com/books/content?id=vdXmDAAAQBAJ&printsec=frontcover&img=1&zoom=5&edge=curl&source=gbs_api", "thumbnail": "http://books.google.com/books/content?id=vdXmDAAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api" }, "language": "en", "previewLink": "http://books.google.com/books?id=vdXmDAAAQBAJ&printsec=frontcover&dq=Food&hl=&cd=1&source=gbs_api", "infoLink": "http://books.google.com/books?id=vdXmDAAAQBAJ&dq=Food&hl=&source=gbs_api", "canonicalVolumeLink": "http://books.google.com/books/about/Molly_on_the_Range.html?hl=&id=vdXmDAAAQBAJ" }, "saleInfo": { "country": "US", "saleability": "NOT_FOR_SALE", "isEbook": false }, "accessInfo": { "country": "US", "viewability": "PARTIAL", "embeddable": true, "publicDomain": false, "textToSpeechPermission": "ALLOWED", "epub": { "isAvailable": false }, "pdf": { "isAvailable": false }, "webReaderLink": "http://books.google.com/books/reader?id=vdXmDAAAQBAJ&hl=&printsec=frontcover&output=reader&source=gbs_api", "accessViewStatus": "SAMPLE", "quoteSharingAllowed": false }, "searchInfo": { "textSnippet": "Celebrating Molly's Jewish/Chinese background with recipes for Asian Scotch Eggs and Scallion Pancake Challah Bread and her new hometown Scandinavian recipes for Cardamom Vanilla Cake and Marzipan Mandel Bread, Molly on the Range will ..." } }, { "kind": "books#volume", "id": "DY-dBAAAQBAJ", "etag": "t4JLTMFKOGc", "selfLink": "https://www.googleapis.com/books/v1/volumes/DY-dBAAAQBAJ", "volumeInfo": { "title": "Real Baby Food", "subtitle": "Easy, All-Natural Recipes for Your Baby and Toddler", "authors": [ "Jenna Helwig" ], "publisher": "Houghton Mifflin Harcourt", "publishedDate": "2015-04-28", "description": "Simple Recipes for a Wholesome Start Nothing compares with making your own baby food: It's fresh and unprocessed, you choose what goes into it, and it is a delicious way to introduce your child to a world of flavors. In Real Baby Foo
10-09 20:50:36.861 32119-32463/com.ovidioreyna.android.googlebooksapiapp I/MainActivity: Length of books array: 10
I've also added a log event to show how long the array is and it shows up as 10. Which is strange since only two instances were written from the HttpRequest method.
You've returned the books too early in a for-loop. Check it carefully in BooksActivity line 144-186.
for (int i = 0; i < itemsArray.length(); i++) {
//checks to see that the Array isn't empty
if (itemsArray.length() > 0) {
JSONObject firstItem = itemsArray.getJSONObject(i);
JSONObject volumeInfo = firstItem.getJSONObject("volumeInfo");
//checks to see if object is null, if not then executes code
if (!volumeInfo.isNull("title")) {
bookTitle = volumeInfo.getString("title");
}
//checks to see if object is null, if not then executes code
if (!volumeInfo.isNull("subtitle")) {
bookSubtitle = volumeInfo.getString("subtitle");
}
//creates an jsonArray object from the authors array
JSONArray authorArray = volumeInfo.getJSONArray("authors");
if (!authorArray.isNull(i)) {
if (authorArray.length() == 1) {
author = authorArray.getString(i);
} else {
for (int k = 0; k < authorArray.length(); k++) {
//checks to see if object is null, if not then executes code
if (!authorArray.isNull(k)) {
author = authorArray.getString(k) + ",";
}
}
}
}
//checks to see if object is null, if not then executes code
if (!volumeInfo.isNull("publishedDate"))
publishedDate = volumeInfo.getString("publishedDate");
//create a new instance of the Books class
Books book = new Books(bookTitle, bookSubtitle, author, publishedDate);
books.add(book);
}
//See that? You return your books with only one extracted from your itemArray!!!!
return books;
}