11

我正在尝试解析像这样的 JSON 字符串(使用 http://www.json-generator.com生成的 URL )

{
"total": 86, 
"jsonrpc": "2.0", 
"id": 1, 
"result": [
    {
        "startDate": "14/03/2012", 
        "meetingId": "1330", 
        "creator": "Jhon", 
        "lastModified": "02/04/2012", 
        "meetingTitle": "task clarification", 
        "location": "Conf hall", 
        "startTime": "02:00 PM", 
        "createdDate": "14/03/2012", 
        "owner": "Peter", 
        "endTime": "02:30 PM"
    }, 
    {
        "startDate": "20/03/2012", 
        "meetingId": "1396", 
        "creator": "Mr.Hobbs", 
        "lastModified": "07/09/2012", 
        "meetingTitle": "Design Work", 
        "location": "South conf Room", 
        "startTime": "03:30 PM", 
        "createdDate": "19/03/2012", 
        "owner": "Steve Jobs", 
        "endTime": "04:30 PM"
    }, 
    {
        "startDate": "22/03/2012", 
        "meetingId": "1432", 
        "creator": "Robin", 
        "lastModified": "21/03/2012", 
        "meetingTitle": "Do something new", 
        "location": "NA", 
        "startTime": "10:00 AM", 
        "createdDate": "21/03/2012", 
        "owner": "Mr.Bean", 
        "endTime": "11:00 AM"
    }
  ]

}

这是我正在使用的对象类:

public class Country {

String startDate;
 String meetingId;
 String creator;
 String lastModified;
 String meetingTitle;
 String location;
 String startTime;
 String createdDate;
 String owner;
 String endTime;

 public String getStartDate() {
    return startDate;
}
public void setStartDate(String startDate) {
    this.startDate = startDate;
}
public String getMeetingId() {
    return meetingId;
}
public void setMeetingId(String meetingId) {
    this.meetingId = meetingId;
}
public String getCreator() {
    return creator;
}
public void setCreator(String creator) {
    this.creator = creator;
}
public String getLastModified() {
    return lastModified;
}
public void setLastModified(String lastModified) {
    this.lastModified = lastModified;
}
public String getMeetingTitle() {
    return meetingTitle;
}
public void setMeetingTitle(String meetingTitle) {
    this.meetingTitle = meetingTitle;
}
public String getLocation() {
    return location;
}
public void setLocation(String location) {
    this.location = location;
}
public String getStartTime() {
    return startTime;
}
public void setStartTime(String startTime) {
    this.startTime = startTime;
}
public String getCreatedDate() {
    return createdDate;
}
public void setCreatedDate(String createdDate) {
    this.createdDate = createdDate;
}
public String getOwner() {
    return owner;
}
public void setOwner(String owner) {
    this.owner = owner;
}
public String getEndTime() {
    return endTime;
}
public void setEndTime(String endTime) {
    this.endTime = endTime;
}




} 

但它让我感到:

     W/JSONStreamReader(1153): java.lang.IllegalStateException: Expected a name but was NUMBER at line 1 column 8
08-09 01:21:37.629: W/JSONStreamReader(1153): java.lang.IllegalStateException: Expected a name but was NUMBER at line 1 column 8
08-09 01:21:37.629: W/JSONStreamReader(1153):   at com.google.gson.stream.JsonReader.nextName(JsonReader.java:785)
08-09 01:21:37.629: W/JSONStreamReader(1153):   at com.example.gsontest.MainActivity$MyAsyncTask.doInBackground(MainActivity.java:162)

在Json“id”:1,是数字!是这个原因吗?我正在使用http://www.json-generator.com生成 JSON

我解析 Json 的 Aysc 代码:

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

        private static final int REGISTRATION_TIMEOUT = 3 * 1000;
        private static final int WAIT_TIMEOUT = 30 * 1000;
        private final HttpClient httpclient = new DefaultHttpClient();

        final HttpParams params = httpclient.getParams();
        private boolean error = false;

        protected Void doInBackground(String... urls) {

            String URL = null;
            Log.d("ConnManagerParams", "ok?");
            try {

                // URL passed to the AsyncTask
                URL = urls[0];
                HttpConnectionParams.setConnectionTimeout(params,
                        REGISTRATION_TIMEOUT);
                HttpConnectionParams.setSoTimeout(params, WAIT_TIMEOUT);
                ConnManagerParams.setTimeout(params, WAIT_TIMEOUT);

                Log.d("ConnManagerParams", "ok?");
                HttpPost httpPost = new HttpPost(URL);
                Log.d("httpPost", "ok?");
                // Response from the Http Request
                HttpResponse response = httpclient.execute(httpPost);
                Log.d("response", "ok?");
                // Check the Http Request for success
                StatusLine statusLine = response.getStatusLine();
                Log.d("statusLine", response.getStatusLine().toString());
                // Log.d("RESPONSE",
                // EntityUtils.toString(response.getEntity()));

                if (statusLine.getStatusCode() == HttpStatus.SC_OK) {
                    // Log.d("statusok", statusLine.getStatusCode());
                    Gson gson = new Gson();
                    // create a new JSON reader from the response input stream
                    Log.d("gson", "gson?");
                    JsonReader jsonReader = new JsonReader(
                            new InputStreamReader(response.getEntity()
                                    .getContent(), "UTF-8"));
                    // begin parsing
                    Log.d("AFTjsonReader", "AFTjsonReader?");
                    jsonReader.beginObject();
                    Log.d("beginObject", "beginObject?");
                    // stay in loop as long as there are more data elements
                    while (jsonReader.hasNext()) {
                        // get the element name
                        Log.d("whilejsonReader", "whilejsonReader?");
                        // String name = jsonReader.nextName();
                        Log.d("nextName", jsonReader.nextName());
                        String name = jsonReader.nextName();

                        Log.d("nextNametest2", "nextName?");

                        if (name.equals("result")) {

                            Log.d("result", "result?");
                            jsonReader.beginArray();

                            while (jsonReader.hasNext()) {
                                // parse every element and convert that to a
                                // country object
                                Country country = gson.fromJson(jsonReader,
                                        Country.class);
                                // add the country object to the list
                                countryList.add(country);

                            }
                            jsonReader.endArray();
                        }

                        // success = jsonReader.nextBoolean();
                        success = true;

                    }
                    // end reader and close the stream
                    jsonReader.endObject();
                    jsonReader.close();

                } else {
                    // Closes the connection.
                    Log.d("Closes the connection.", "Closes the connection.?");
                    Log.w(LOG_TAG, statusLine.getReasonPhrase());
                    response.getEntity().getContent().close();
                    throw new IOException(statusLine.getReasonPhrase());
                }

            } catch (Exception e) {
                Log.d("catch", "catch");
                Log.w(LOG_TAG, e);

                error = true;
                cancel(true);
            }

            return null;

        }

        protected void onCancelled() {
            Log.e(LOG_TAG, "Error occured during data download");
        }

        protected void onPostExecute(Void unused) {
            if (error) {
                Log.e(LOG_TAG, "Data download ended abnormally!");
            } else {
                displayCountries();
            }
        }

    }

}

任何想法我应该如何解决它?

谢谢!

4

3 回答 3

18

您的代码中的问题是您循环使用名称(json 键):

while (jsonReader.hasNext()) {

你得到下一个名字:

String name = jsonReader.nextName();

但是只有当这个名字等于时你才会使用这个值result

将其JsonReader视为在 json 中向前移动光标的一种方式:逐个标记读取它。您给它的每个命令要么读取光标指向的内容,要么移动光标,有时您可以移动光标并使用单个命令读取值(如使用nextName())。

当名称不是停留在您离开它的位置时:您刚刚读取的名称或result键。jsonReadernextName()

所以下次它调用nextName()光标从键移动到值(next)并且它希望找到 aname而是找到前一个名称的值,在你的情况下NUMBER,因为你的 json 中的第一个值是一个数字(名称:"total", 值: 56)。

如果您因为不在乎而没有读取该值,则应致电

jsonReader.skipValue();

意味着你应该改变你的代码

if (name.equals("result")) {
  // read it
} else {
  jsonReader.skipValue();
}

也就是说:您应该使用注释,或者,如果由于某种原因不能,请注册一个或多个TypeAdapter来解析您的自定义对象。

这些适配器中的代码与您编写的代码非常相似,但仅限于与您的对象匹配的 json 的单个部分。

因此,例如,如果您创建一个CountriesResult包含total, 和result类型的类List<Country>

public class CountriesResult {
  private int total;
  @SerializedName("result")
  private List<Country> countries;
}

您已经有一个 Country 类,其中包含您需要的字段。

然后你让GSon解析你的CountriesResult对象,它会自动解析它。

gson.fromJson(jsonString, CountriesResult.class);

如果您需要以Country自定义方式解析,您只需要一个TypeAdatperfor Country,请参阅示例。并注册类型适配器或使用@JsonAdapter 注解

于 2016-02-01T16:27:54.337 回答
3

如果您要JsonReader手动使用和解析流,则不要使用通过Gson.fromJson().

一旦进入循环,您要么需要在遍历该数组时从每个对象中提取字段,要么只需将自动反序列化与适当的类一起使用(老实说,这是您应该做的):

class Response {
    private int total;
    private String jsonrpc;
    private int id;
    private List<Country> result;

   // getters and setters ...
}

然后简单地说:

InputStreamReader isr = new InputStreamReader(response.getEntity()
                                .getContent(), "UTF-8"));
Response r = gson.fromJson(isr, Response.class);
于 2013-08-09T17:35:39.140 回答
2

我也面临同样的问题。我发现,问题是我得到 jsonReader.nextName() 的每个 if 条件。这不是正确的方法。我认为你也在做同样的事情。

从您的代码中,这两行会产生问题。

  // here the jsonReader moving one step.
  Log.d("nextName", jsonReader.nextName());

  //again your trying to getting the "jsonReader.nextName()" it is wrong in the above line already you got the name and reader move to next line. So  Exception may be comes here.                                    
   String name = jsonReader.nextName();   

我们应该只在while循环中的每次迭代中使用一次“jsonReader.nextName()”,比如

 while (reader.hasNext())
 {

            String name=reader.nextName();
            if(name.equals(Constants.AUTH)){
                authDetails.setAuth(reader.nextString());

            }else if(name.equals(Constants.STATUS)){
                authDetails.setStatus(reader.nextInt());
            }else if(name.equals(Constants.MESSAGE)){
                authDetails.setMessage(reader.nextString());
            }else {
                reader.skipValue();
            }

    }
于 2016-07-21T11:54:16.147 回答