1

I have a rather specific question about JSON parsing in Android.

I have a requirement to download a single JSON array containing information in the format shown below, the number of JSON objects in the array is variable. I need to retrieve all the JSON values in the array so each JSON value has to be stored as an android list named after the common JSON keys because there are many instances of each, e.g. a list for placenames keys [place1,place2,place3 = placename list], a list for questions key, etc. A caveat to this is I cannot use an android array to store these JSON key values since each time my app runs this download task I don't know how many JSON objects will be in the single array. Users can submit as much as they want at any time to the database.

[
{
    "placename": "place1",
    "latitude": "50",
    "longitude": "-0.5",
    "question": "place1 existed when?",
    "answer1": "1800",
    "answer2": "1900",
    "answer3": "1950",
    "answer4": "2000",
    "correctanswer": "1900"
},
{
    "placename": "place2",
    "latitude": "51",
    "longitude": "-0.5",
    "question": "place2 existed when?",
    "answer1": "800",
    "answer2": "1000",
    "answer3": "1200",
    "answer4": "1400",
    "correctanswer": "800"
},
{
    "placename": "place3",
    "latitude": "52",
    "longitude": "-1",
    "question": "place 3 was established when?",
    "answer1": "2001",
    "answer2": "2005",
    "answer3": "2007",
    "answer4": "2009",
    "correctanswer": "2009"
}
]

Below is my code for mainactivity which I managed to get working but had a derp moment and realised I'd simply gone through and parsed out the values for each JSON key in each object as a single string value for each JSON key. Since the loop iterates it merely overwrites at each stage - the placename string is "place1", then "place2", then "place3" by the end of the loop, rather than ["place1","place2", "place3"] which is what I want. My question now is how would I go about parsing the JSONArray to extract all instances of each JSON value and output as a string list for each JSON key, the length of the list is determined by the number of Objects?

I've already got the template for a string list that stores all the JSON key values (commented out in the below code) but I'm not sure how to fill that String list from the JSON parsing process.

I've had a good look around and couldn't find anything specifically about JSON Array to Android List so help would be greatly appreciated. I'd also like to know if there is a way of maintaining association between each list (e.g. questions & answers for specific placenames) if I bundle the data out to different activities (e.g. q&a to a quiz and placenames/lat/lon to GPS). Can I do this by referencing the same index in the list? Or would I need to store these lists in local storage? an SQL lite database?

Thanks for your time and sorry for the overwhelmingly long post!

public class MainActivity extends Activity {

// The JSON REST Service I will pull from
static String dlquiz = "http://www.example.php";


// Will hold the values I pull from the JSON 
//static List<String> placename = new ArrayList<String>();
static String placename = "";
static String latitude = "";
static String longitude = "";
static String question = "";
static String answer1 = "";
static String answer2 = "";
static String answer3 = "";
static String answer4 = "";
static String correctanswer = "";

@Override
public void onCreate(Bundle savedInstanceState) {
    // Get any saved data
    super.onCreate(savedInstanceState);

    // Point to the name for the layout xml file used
    setContentView(R.layout.main);

    // Call for doInBackground() in MyAsyncTask to be executed
    new MyAsyncTask().execute();

}
// Use AsyncTask if you need to perform background tasks, but also need
// to change components on the GUI. Put the background operations in
// doInBackground. Put the GUI manipulation code in onPostExecute

private class MyAsyncTask extends AsyncTask<String, String, String> {

    protected String doInBackground(String... arg0) {

        // HTTP Client that supports streaming uploads and downloads
        DefaultHttpClient httpclient = new DefaultHttpClient(new BasicHttpParams());

        // Define that I want to use the POST method to grab data from
        // the provided URL
        HttpPost httppost = new HttpPost(dlquiz);

        // Web service used is defined
        httppost.setHeader("Content-type", "application/json");

        // Used to read data from the URL
        InputStream inputStream = null;

        // Will hold the whole all the data gathered from the URL
        String result = null;

        try {

            // Get a response if any from the web service
            HttpResponse response = httpclient.execute(httppost);        

            // The content from the requested URL along with headers, etc.
            HttpEntity entity = response.getEntity();

            // Get the main content from the URL
            inputStream = entity.getContent();

            // JSON is UTF-8 by default
            // BufferedReader reads data from the InputStream until the Buffer is full
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"), 8);

            // Will store the data
            StringBuilder theStringBuilder = new StringBuilder();

            String line = null;

            // Read in the data from the Buffer untilnothing is left
            while ((line = reader.readLine()) != null)
            {

                // Add data from the buffer to the StringBuilder
                theStringBuilder.append(line + "\n");
            }

            // Store the complete data in result
            result = theStringBuilder.toString();

        } catch (Exception e) { 
            e.printStackTrace();
        }
        finally {

            // Close the InputStream when you're done with it
            try{if(inputStream != null)inputStream.close();}
            catch(Exception e){}
        }


        //Log.v("JSONParser RESULT ", result);

        try {               
            JSONArray array = new JSONArray(result);

            for(int i = 0; i < array.length(); i++)
            {
                JSONObject obj = array.getJSONObject(i);

                //now, get whatever value you need from the object:
                placename = obj.getString("placename");
                latitude = obj.getString("latitude");
                longitude = obj.getString("longitude");
                question = obj.getString("question");
                answer1 = obj.getString("answer1");
                answer2 = obj.getString("answer2");
                answer3 = obj.getString("answer3");
                answer4 = obj.getString("answer4");
                correctanswer = obj.getString("correctanswer");    
            }               
            } catch (JSONException e){
                e.printStackTrace();
            }
        return result;

    }

    protected void onPostExecute(String result){

        // Gain access so I can change the TextViews
        TextView line1 = (TextView)findViewById(R.id.line1); 
        TextView line2 = (TextView)findViewById(R.id.line2); 
        TextView line3 = (TextView)findViewById(R.id.line3); 

        // Change the values for all the TextViews
        line1.setText("Place Name: " + placename); 
        line2.setText("Question: " + question); 
        line3.setText("Correct Answer: " + correctanswer);

    }

}

}
rtg93
  • 23
  • 2
  • 6
  • You're almost there. You just need an ArrayList to add the values in it. Best approach will be to make a pojo class for all the Json items and then add the values via that. – Tushar Gogna Apr 10 '15 at 10:53
  • check [here](http://stackoverflow.com/questions/29513967/parsing-json-on-android-eclipse/29514337#29514337). Maybe you will be inspired. – SilentKnight Apr 10 '15 at 11:30

3 Answers3

-1

Instead of keeping variables:

static String placename = "";
static String latitude = "";
static String longitude = "";
static String question = "";
static String answer1 = "";
static String answer2 = "";
static String answer3 = "";
static String answer4 = "";
static String correctanswer = "";

make Bean Class having all these variables. Make array list of bean and during parsing make bean objects and add to list.

Bean Class:

public class ModelClass{
private String latitude = "";
private String longitude = "";
private String question = "";
private String answer1 = "";
private String answer2 = "";
private String answer3 = "";
private String answer4 = "";
private String correctanswer = "";
// ....
// Getter Setters and constructors
// .......
}


ArrayList<ModelClass> mList=new ArrayList<ModelClass>();

In for loop of json parsing:

 JSONObject obj = array.getJSONObject(i);
 ModelObject object=new ModelObject();
 // parse and make ModelObject
 list.add(object);

Try using this approach. It will work.

seema
  • 991
  • 1
  • 13
  • 27
  • I want to collect my values as static List placename = new ArrayList(); rather than static String placename = ""; this is still collecting them as strings but then making a list from all the different objects? I want to make a list of all instances of each object (a list of all placenames, a list of all latitudes, etc). Would your answer enable me to do that? – rtg93 Apr 10 '15 at 11:38
  • You will get List of ModelObjects and each ModelObject will have placename, latitude etc – seema Apr 10 '15 at 11:52
-1

you should divide your objects into classes, and use the GSON json parser.

look at this answer on how to parse a json array into objects:

JSON parsing using Gson for Java

a good approach would be a class question that contains a list of subclasses called possibleanswers, those have a boolean attribute ( correct : true, incorrect: false) to check if the user has clicked the correct one.

if you want to store the data, you will have to use sqllite or any of the many libraries like ActiveAndroid.

Community
  • 1
  • 1
CptEric
  • 897
  • 9
  • 23
  • Thanks for the response. I already have a method of determining what the question and answer the user provided using radio buttons. It sends unchecked or checked for each possible answer back to the server and then echos the correctanswer to the user after they've hit submit. What kind of advantage what putting all objects into classes bring? – rtg93 Apr 10 '15 at 11:43
  • easy data handling, correctness ( it's quite dirty to keep things in variables when they have a context) , and ofcourse the possibility to play with arraylists and objects when searching... – CptEric Apr 10 '15 at 13:21
-1

I see that you are accessing this JSON file form a Remote Service. On that basis, you will need to structure your code in a manner that will work around how many instances are in the physical JSON file.

Your issue is here:

 JSONArray array = new JSONArray(result);

            for(int i = 0; i < array.length(); i++)
            {
                JSONObject obj = array.getJSONObject(i);

You are telling it that the entire JSON file has an array, which contains a length, which is incorrect.

Curly Brackets ("{") represent a JSONObject, and Square Brackets ("[") represent a JSON Array.

Based on your JSON file:

[
{
    "placename": "place1",
    "latitude": "50",
    "longitude": "-0.5",
    "question": "place1 existed when?",
    "answer1": "1800",
    "answer2": "1900",
    "answer3": "1950",
    "answer4": "2000",
    "correctanswer": "1900"
},

You are dealing with one JSONArray, and this array has to no reference name give to it, rather a place index.

Heres what you need to try:


public class ListCreator{

    private List<String> placename;

    public ListCreator() {
         placename = new ArrayList<String>();
    }

    public void addPlaceName(String s)
    {
        answers.add(s);
    }

    public String[] getAnswers()
    {
        return placename.toArray(new String[1]);
    }
}

Bear in mind that is just a snippet of what the class will look like only for the "placename" fields.

Now to your JSON:


You will need to initialize a Vector Variable for each List you want to create:

private Vector<ListCreator> placeNameVec;

Next you will need to set a method for each part of the JSONArray:

public Vector getPlaceNames(){
    return placeNameVector;
}

JSONArray array = new JSONArray(result);

for(int x = 0; x < 3; x++){
    JSONObject thisSet = array.getJSONObject(x);
    ListCreator placeNames = new ListCreator();
    placeNames.addPlaceName(thisSet.getString("placename"));

}
placeNameVec.add(placeNames);

That should get you going on what you are trying to answer.

So basically bear in mind that you you can't specify the "array.length()".

Hope this helps!

Please let me know of the outcome :)

If you get into any further difficulty, this Tutorial on JSONParsing really did help me when I was confused.

All the best

TejjD
  • 2,571
  • 1
  • 17
  • 37
  • Okay after coming to my senses I can see your solution works but I phrased my issue wrong. Your code outputs the JSON values (placename, etc) of each of the three example objects as strings but at each iteration of the loop the next set of JSON values overwrite the previous values so at the loop's end all the strings are for the third object, starting with {"placename":"place3"...}. I don't think I explained very clearly but I'd like to keep all JSON values of the same type (Placename, latitude, etc) in a separate list, so (place1, place2, place3) = placenamelist, (50,51,52) = latitudelist – rtg93 Apr 10 '15 at 13:54
  • Thank you for the correction of your issue, I now understand what you require to happen. I recently did exactly what you require, but using Vectors. Let me work out the List one quickly, and I will post the working answer for you. Just to clarify, you want to be able to store all the placenames (for example) into a list, then all the questions into a list, then answer1 into its own list and answer2 into its own list, and so on? – TejjD Apr 10 '15 at 18:06
  • Yep, in a nutshell that's exactly what I'm using for. Thanks for your help. – rtg93 Apr 10 '15 at 18:15
  • I just edited my answer, please have a look at how I have structured a possible solution to your issue. Do inform me of the outcome :) Good Luck! – TejjD Apr 10 '15 at 18:56