Ошибка синтаксического анализа Jsonreader

У меня есть следующий код:

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

Он возвращает следующий 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
  }
}

Я разбираю ридер следующим образом:

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());
}

Я получаю следующую ошибку:

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)

Есть ли способ разобрать Jsonreader по-другому? Мне нужны значения таких полей, как день рождения, end_term, bioguide_id и т. д. Разбирать их вручную, как это, сложно, и мне приходится делать много других вызовов API, которые могут возвращать разные результаты Json, тогда мне снова приходится тратить время на их разбор. Я пытался использовать BufferedReader, но это дает ошибку «Недостаточно памяти» в случае возврата большого файла Json.


person Zxxxxx    schedule 15.11.2016    source источник
comment
Возможный дубликат Как анализировать JSON в Android   -  person OneCricketeer    schedule 15.11.2016
comment
Я думаю, что это не дубликат, потому что я не могу использовать BufferedReader, потому что он дает OutOfMemory для больших возвратов Json.   -  person Zxxxxx    schedule 15.11.2016
comment
Это не важная часть. Вы получаете строку, помещаете ее в new JSONObject и начинаете синтаксический анализ.   -  person OneCricketeer    schedule 15.11.2016
comment
Я чувствую, что мне нужно отредактировать эту строку... reader = new JsonReader(new InputStreamReader(con.getInputStream()));... не могли бы вы рассказать мне, как это сделать, потому что раньше я использовал BufferedReader br=new BufferedReader(new InputStreamReader (con.getInputStream())); и это дало мне проблему с памятью   -  person Zxxxxx    schedule 15.11.2016
comment
Если вы хотите продолжить использование InputStream, вам нужно вызвать endObject() и endArray() соответственно.   -  person OneCricketeer    schedule 15.11.2016
comment
@cricket_007.. Я хочу использовать JSONObject так, как вы предложили. Не могли бы вы рассказать мне, как преобразовать этот ... новый JsonReader (новый InputStreamReader (con.getInputStream ())) ... в JSONObject ??   -  person Zxxxxx    schedule 15.11.2016
comment
Если ваша строка не помещается в памяти, то я не думаю, что вы можете. Как вы сказали, вы пытались, но это не работает   -  person OneCricketeer    schedule 15.11.2016


Ответы (2)


Посмотрите внимательно на свой код:

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

Когда «день рождения» является именем свойства, вы не используете значение, поэтому при следующем проходе цикла вы вызываете nextName(), но синтаксический анализатор все еще находится на значении.

Используйте это вместо этого:

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

Кроме того, как указывалось в комментариях, вам нужно иметь соответствие endObject() для каждого beginObject() и соответствие endArray() для каждого beginArray().

person kris larson    schedule 15.11.2016
comment
Спасибо...пост помечен как дубликат...как его удалить?? - person Zxxxxx; 15.11.2016
comment
этот код a/ не компилируется, а b/ имел бы удивительные результаты, если бы компилировался. - person njzk2; 15.11.2016
comment
В комментарии был предложен дубликат @Anirban, но Q не помечен как таковой, так что не беспокойтесь. :) - person kris larson; 16.11.2016

Я предполагаю, что вы совершаете сетевые вызовы, используя AsyncTask. Это утомительно, и вы можете сделать много очень плохих вещей (https://www.youtube.com/watch?v=jtlRNNhane0) таким образом. Вы намного лучше используете такие библиотеки, как OkHttp (используется HttpUrlConnection под капотом), Retrofit, Volley, Picasso и т. д. Это не только снижает сложность, но и в некоторых ситуациях работает намного быстрее, чем AsyncTasks (http://instructure.github.io/blog/2013/12/09/volley-vs-retrofit/).

Использование такой библиотеки, как Retrofit, означает, что вы можете использовать FactoryConverter для автоматического преобразования JSON в ваш POJO (нет необходимости читать его вручную). Все, что вам нужно сделать, это создать POJO, соответствующий вашему JSON(http://www.jsonschema2pojo.org/) и определите интерфейс API и обратный вызов, а Retrofit позаботится обо всем остальном.

Чтобы использовать Retrofit с конвертером Gson, добавьте следующие зависимости в файл сборки gradle:

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

Вот простой пример класса Service, использующего преобразователь Gson для преобразования в POJO:

Сначала создайте класс интерфейса для определения вызовов API:

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

Затем создайте его экземпляр, используя (реализация позаботится о модернизации):

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

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

Затем вы делаете вызов, используя:

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

Вы получаете POJO вашего определения, уже преобразованного из JSON.

Взгляните на следующие ресурсы, чтобы лучше понять это:

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

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

IMO лучшая документация по модернизации: https://futurestud.io/tutorials/retrofit-getting-started-and-android-client

person Veneet Reddy    schedule 15.11.2016
comment
это хорошо, но это не отвечает на вопрос. - person njzk2; 15.11.2016
comment
Разбирать его вручную, как это, сложно, и мне приходится делать много других вызовов API, которые могут возвращать разные результаты Json, тогда мне снова приходится тратить время на его разбор. Я пытался использовать BufferedReader, но это дает ошибку «Недостаточно памяти» в случае возврата большого файла Json. Я отвечал на это.. - person Veneet Reddy; 16.11.2016