0

I have a the following code:

reader = new JsonReader(new InputStreamReader(con.getInputStream()));

It returns the following JSON:

{
  "results": [
    {
      "bioguide_id": "D000626",
      "in_office": true,
      "thomas_id": "02296",
      "govtrack_id": "412675",
      "crp_id": "N00038767",
      "fec_ids": [
        "H6OH08315"
      ],
      "first_name": "Warren",
      "nickname": null,
      "last_name": "Davidson",
      "middle_name": null,
      "name_suffix": null,
      "gender": "M",
      "birthday": "1970-03-01",
      "leadership_role": null,
      "term_start": "2016-06-09",
      "term_end": "2017-01-03",
      "state": "OH",
      "state_name": "Ohio",
      "party": "R",
      "title": "Rep",
      "chamber": "house",
      "phone": "202-225-6205",
      "fax": null,
      "website": null,
      "office": "1011 Longworth House Office Building",
      "contact_form": null,
      "votesmart_id": 166760,
      "district": 8,
      "oc_email": null,
      "ocd_id": "ocd-division/country:us/state:oh/cd:8"
    },
    {
      "bioguide_id": "L000585",
      "in_office": true,
      "thomas_id": "02295",
      "govtrack_id": "412674",
      "crp_id": "N00037031",
      "fec_ids": [
        "H6IL18088"
      ],
      "first_name": "Darin",
      "nickname": null,
      "last_name": "LaHood",
      "middle_name": null,
      "name_suffix": null,
      "gender": "M",
      "birthday": "1968-07-05",
      "leadership_role": null,
      "term_start": "2015-09-17",
      "term_end": "2017-01-03",
      "state": "IL",
      "state_name": "Illinois",
      "party": "R",
      "title": "Rep",
      "chamber": "house",
      "phone": "202-225-6201",
      "fax": null,
      "website": "https://lahood.house.gov/",
      "office": "2464 Rayburn House Office Building",
      "contact_form": "https://lahood.house.gov/contact/email",
      "votesmart_id": 128760,
      "district": 18,
      "oc_email": "Rep.Lahood@opencongress.org",
      "twitter_id": "RepLaHood",
      "youtube_id": null,
      "facebook_id": "1499570210366431",
      "ocd_id": "ocd-division/country:us/state:il/cd:18"
    }
  ],
  "count": 538,
  "page": {
    "count": 2,
    "per_page": 2,
    "page": 1
  }
}

I parse the reader in the following way:

try {

    reader.beginObject();
    while (reader.hasNext()) {
        String name = reader.nextName();
        if (name.equals("results")){
            reader.beginArray();
            while (reader.hasNext()) {
                reader.beginObject();
                while (reader.hasNext()) {
                    String id = reader.nextName();
                    if(id.equals("birthday"))
                        Log.d("id", id);
                    else
                        reader.skipValue();
                }
            }
        }

        else {
            reader.skipValue();
        }
    }

}
catch (IOException e){
    Log.w("Error",e.getMessage());
}

I get the following error:

E/AndroidRuntime: FATAL EXCEPTION: main
                  Process: com.app.congress.congressapp, PID: 5095
java.lang.IllegalStateException: Expected a name but was STRING
   at android.util.JsonReader.nextName(JsonReader.java:390)
   at com.app.congress.congressapp.GetAllStates.onPostExecute(ByState.java:57)
   at com.app.congress.congressapp.GetAllStates.onPostExecute(ByState.java:30)
   at android.os.AsyncTask.finish(AsyncTask.java:636)
   at android.os.AsyncTask.access$500(AsyncTask.java:177)
   at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:653)
   at android.os.Handler.dispatchMessage(Handler.java:102)
   at android.os.Looper.loop(Looper.java:135)
   at android.app.ActivityThread.main(ActivityThread.java:5254)
   at java.lang.reflect.Method.invoke(Native Method)
   at java.lang.reflect.Method.invoke(Method.java:372)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
E/AndroidRuntime: Error reporting crash
android.os.DeadObjectException
   at android.os.BinderProxy.transactNative(Native Method)
   at android.os.BinderProxy.transact(Binder.java:496)
   at android.app.ActivityManagerProxy.handleApplicationCrash(ActivityManagerNative.java:4164)
   at com.android.internal.os.RuntimeInit$UncaughtHandler.uncaughtException(RuntimeInit.java:89)
   at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:693)
   at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:690)

Is there is way to parse the Jsonreader in a different way? I want the values of fields like birthday, end_term, bioguide_id etc. Parsing it manually like this is difficult and I have to make many other API calls which may return different Json results then again I have to spend time parsing it. I tried to use BufferedReader but that gives an Out Of Memory error in case of large Json file return.

Floern
  • 33,559
  • 24
  • 104
  • 119
Zxxxxx
  • 397
  • 1
  • 5
  • 16
  • 1
    Possible duplicate of [How to parse JSON in Android](http://stackoverflow.com/questions/9605913/how-to-parse-json-in-android) – OneCricketeer Nov 15 '16 at 19:06
  • Its not a duplicate I think because I cannot use BufferedReader because it gives OutOfMemory for large Json returns. – Zxxxxx Nov 15 '16 at 19:09
  • That isn't the important piece. You get a string, you put it into a `new JSONObject`, and you start parsing – OneCricketeer Nov 15 '16 at 19:10
  • I feel like I have to edit this line...reader = new JsonReader(new InputStreamReader(con.getInputStream()));...can you please tell me how because earlier I was using BufferedReader br=new BufferedReader(new InputStreamReader(con.getInputStream())); and it gave me out of memory issue – Zxxxxx Nov 15 '16 at 19:12
  • If you want to continue using the InputStream, you need to call `endObject()` and `endArray()` accordingly – OneCricketeer Nov 15 '16 at 19:12
  • @cricket_007..I want to use the JSONObject way you suggested can you please tell me how to convert this...new JsonReader(new InputStreamReader(con.getInputStream()))...to a JSONObject?? – Zxxxxx Nov 15 '16 at 19:17
  • If your string doesn't fit in memory, then I don't think you can. As you said, you tried, but it isn't working – OneCricketeer Nov 15 '16 at 19:18

2 Answers2

3

Look carefully at your code:

                        String id = reader.nextName();
                        if(id.equals("birthday"))
                            Log.d("id", id);
                        else
                            reader.skipValue();

When "birthday" is the property name, you don't consume the value, so on the next pass through the loop, you call nextName() but the parser is still on the value.

Use this instead:

                        String id = reader.nextName();
                        if(id.equals("birthday")) {
                            Log.d("id", id);
                            reader.nextString(); // or reader.skipValue()
                        } else {
                            reader.skipValue();
                        }

Also as comments have pointed out, you need to have a matching endObject() for each beginObject() and a matching endArray() for each beginArray().

kris larson
  • 30,387
  • 5
  • 62
  • 74
0

I assume you are making network calls using AsyncTask. This is tedious and you can do a lot of very bad things(https://www.youtube.com/watch?v=jtlRNNhane0) this way. You are much, much better of using libraries like OkHttp(Used by HttpUrlConnection under the hood), Retrofit, Volley, Picasso, etc. It not only reduces complexity but also is much faster than AsyncTasks in some situations(http://instructure.github.io/blog/2013/12/09/volley-vs-retrofit/).

Using a library like Retrofit means that you can use a FactoryConverter to convert JSON into your POJO automatically(No need to read it manually). All you need to do is create a POJO to match your JSON(http://www.jsonschema2pojo.org/) and define the API interface and a callback and Retrofit will take care of the rest.

To use Retrofit with Gson converter add the following dependencies to your gradle build file:

compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.0.2'

Here's a simple example of a Service class using a Gson converter to convert to a POJO:

First create an interface class to define your API calls:

public interface GitHubService {
  @GET("users/{user}/repos")
  Call<List<Repo>> listRepos(@Path("user") String user);
}

Then create an instance of it using (Implementation taken care of by Retrofit):

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com")
    .addConverterFactory(GsonConverterFactory.create())
    .build();

GitHubService service = retrofit.create(GitHubService.class);

Then you make a call using:

Call<List<Repo>> repos = service.listRepos("octocat");

You get a POJO of your definition already converted from JSON.

Take a look the following resources to get a better hang of it:

https://square.github.io/retrofit/

https://github.com/square/retrofit/

IMO the best documentation of Retrofit: https://futurestud.io/tutorials/retrofit-getting-started-and-android-client

Veneet Reddy
  • 2,707
  • 1
  • 24
  • 40
  • that's nice, but that does not answer the question. – njzk2 Nov 15 '16 at 20:48
  • "Parsing it manually like this is difficult and I have to make many other API calls which may return different Json results then again I have to spend time parsing it. I tried to use BufferedReader but that gives an Out Of Memory error in case of large Json file return." I was answering this.. – Veneet Reddy Nov 16 '16 at 06:53