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": "[email protected]",
      "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.

7
  • 1
    Possible duplicate of How to parse JSON in Android Commented Nov 15, 2016 at 19:06
  • Its not a duplicate I think because I cannot use BufferedReader because it gives OutOfMemory for large Json returns. Commented Nov 15, 2016 at 19:09
  • That isn't the important piece. You get a string, you put it into a new JSONObject, and you start parsing Commented Nov 15, 2016 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 Commented Nov 15, 2016 at 19:12
  • If you want to continue using the InputStream, you need to call endObject() and endArray() accordingly Commented Nov 15, 2016 at 19:12

2 Answers 2

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().

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks...the post is marked as a duplicate...how can I get it removed??
that code a/ does not compile and b/ would have surprising results if it didi.
@Anirban duplicate was suggested in comment, but Q is not marked as such, so no worries. :)
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

2 Comments

that's nice, but that does not answer the question.
"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..

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.