2014-10-17 40 views
1

我意识到我的问题已经被问了很多,但我花了大量的时间搜索SO和谷歌,试图更好地理解这个概念,但没有成功。我见过很多不同的实现,这就是让我得到一些关于我的具体情况的建议。在java中使用GSON解析JSON并填充列表视图

我的目标

我需要执行一个POST请求的PHP文件,目标是最终填充字段列表中的活动与一些JSON数据。

HTTP POST响应

这里是我收到来自服务器,这似乎是阵列的JSON对象返回的响应数据的格式(?)。

{"expense":[{"cat_id_PK":237,"cat_name":"Name1","cat_amount":"100.00","is_recurring":0}, 
    {"cat_id_PK":238,"cat_name":"Name2","cat_amount":"200.00","is_recurring":0}, 
    {"cat_id_PK":239,"cat_name":"Name3","cat_amount":"300.00","is_recurring":0}, 
    {"cat_id_PK":240,"cat_name":"Name4","cat_amount":"400.00","is_recurring":0}], 
    "expense_rec": [{"cat_id_PK":207,"cat_name":"Name5","cat_amount":"500.00","is_recurring":1}]} 

第一个问题

下面的代码是我用来读取响应什么。这是我应该如何处理?看起来很奇怪,得到一个json编码的响应,然后将其更改为一个字符串,只是试图再次访问json对象的元素。我在这里错了吗?

//This code is in the doInBackground method of my "sendPostRequest" async task. 
HttpResponse httpResponse = httpClient.execute(httpPost); 

InputStream inputStream = httpResponse.getEntity().getContent(); 
InputStreamReader inputStreamReader = new InputStreamReader(inputStream); 
BufferedReader bufferedReader = new BufferedReader(inputStreamReader); 

StringBuilder stringBuilder = new StringBuilder(); 
String bufferedStrChunk = null; 

while ((bufferedStrChunk = bufferedReader.readLine()) != null) { 
     stringBuilder.append(bufferedStrChunk); 
} 
//Returns string to onPostExecute() 
return stringBuilder.toString(); 

第二个问题

我有一个名为“PostResponse.java”保存下面的代码我的教程仿照网上的另一个文件。我不确定如何从onPostExecute方法与此类进行交互。我该如何访问第一个对象中的第一个项目(类似于PHP,您可以这样做:费用[0] ['cat_name'])。我试图用各种方式做到这一点,但没有成功。这里是PostResponse.java类:

public class PostResponse { 
public Integer cat_id_PK; 
public String cat_name; 
public BigDecimal cat_amount; 
public Integer is_recurring; 

public int getID() { 
    return this.cat_id_PK; 
} 
public void setID(int cat_id_PK){ 
    this.cat_id_PK = cat_id_PK; 
} 

public String getName() { 
    return this.cat_name; 
} 
public void setName(String cat_name) { 
    this.cat_name = cat_name; 
} 

public BigDecimal getAmount() { 
    return this.cat_amount; 
} 
public void setAmount(BigDecimal cat_amount) { 
    this.cat_amount = cat_amount; 
} 

public int getRecurring() { 
    return this.is_recurring; 
} 
public void setRecurring(int is_recurring) { 
    this.is_recurring = is_recurring; 
} 

@Override 
public String toString() { 
    StringBuilder sb = new StringBuilder(); 
    sb.append("*** Categories ***"); 
    sb.append("cat_id_PK="+getID()+"\n"); 
    sb.append("cat_name="+getName()+"\n"); 
    sb.append("cat_amount="+getAmount()+"\n"); 
    sb.append("is_recurring="+getRecurring()+"\n"); 

    return sb.toString(); 
} 

}

,这里是我的onPostExecute方法的内容:

protected void onPostExecute(String result) { 
    super.onPostExecute(result); 

    Gson gson = new Gson();    
    PostResponse response = gson.fromJson(result, PostResponse.class); 
    System.out.println(result); 
} 

就像我最初说,我的最终目标是要填充这些项目到一个列表活动,但在这一点上,我只想知道如何获得特定元素。但是,如果任何人想要在他们的回复中包含如何填充列表活动,那么会为我节省更多麻烦,因为对于我来说,没有任何Java使用起来很容易!

回答

2

FIRST QUESTION

The code below is what I'm using to read the response. Is this how I should be handling that? It seems weird to get a json encoded response and then change it to a string, only to try and access elements of a json object again. Am I on the wrong track here?

这是处理HTTP响应的一种方式。 “json编码响应”只不过是基于文本的响应,所以在接收端将其转换为字符串是有道理的。也就是说,就Java而言,您收到的json不是一个“对象”:它只是对象(或您的案例中的一堆对象)的文本表示形式,作为字节流接收。

这就是说,你可以通过跳过字符串(构建器)部分来缩短代码。 Gson提供了alternative constructor that takes a Reader实例,您可以在代码片段中为BufferedReader提供实例。

作为一个方面:文本json到Java对象的转换是一个潜在的'重'操作。因此,您最好避免在主/ UI线程中执行此操作,因此请将其移动到AsyncTaskdoInBackground()方法中(并适当更改类型)。

SECOND QUESTION

I have another file called "PostResponse.java" that holds the following code I modeled after a tutorial online. I'm unsure of how to interact with this class from the onPostExecute method. How can I access say, the first item in the first object (something like in PHP where you could do: expense[0]['cat_name']). I've tried to do this various ways with no success.

你接近,但如果你更仔细的JSON样品,你会看到你的PostResponse类不是它一个很好的匹配:

{ 
    "expense": [ 
    { 
     "cat_id_PK": 237, 
     "cat_name": "Name1", 
     "cat_amount": "100.00", 
     "is_recurring": 0 
    }, 
    { 
     "cat_id_PK": 238, 
     "cat_name": "Name2", 
     "cat_amount": "200.00", 
     "is_recurring": 0 
    }, 
    { 
     "cat_id_PK": 239, 
     "cat_name": "Name3", 
     "cat_amount": "300.00", 
     "is_recurring": 0 
    }, 
    { 
     "cat_id_PK": 240, 
     "cat_name": "Name4", 
     "cat_amount": "400.00", 
     "is_recurring": 0 
    } 
    ], 
    "expense_rec": [ 
    { 
     "cat_id_PK": 207, 
     "cat_name": "Name5", 
     "cat_amount": "500.00", 
     "is_recurring": 1 
    } 
    ] 
} 

考虑更多的层次上面的格式。第一级有两个(json)对象:expenseexpense_rec(均包含0 ... *个元素,如方括号所示)。这意味着无论你想要将JSON映射到哪个类,都应该定义这些字段。如果你现在看看你的类,它应该变得很明显,就目前的形式而言,它实际上模拟了上述领域的一个子对象。

基本上,类映射JSON上,应该看起来有点像这样:

PostResponse:

public class PostResponse { 

    public ExpenseItem[] expense; 
    public ExpenseItem[] expense_rec; 
    // List<ExpenseItem> is also supported 

    // getters & setters 
} 

的ExpenseItem:

public class ExpenseItem { 

    public Integer cat_id_PK; 
    public String cat_name; 
    public BigDecimal cat_amount; 
    public Integer is_recurring; 

    // getters & setters 
} 

随着定义的模型类,尝试让Gson再次发挥它的魔力。如果一切顺利,你应该能够访问类似的方式将数据你在PHP中使用什么:

// map json to POJOs 
PostResponse response = new Gson().fromJson(bufferedReader, PostResponse.class); 
// retrieve the cat_name for the first item (assuming there is one) 
String catName = response.getExpense()[0].getName(); 

...或者通过ExpenseItem定义的干将其他领域。

一旦你有这个部分的工作,将一个适配器的数组或费用列表提供给一个适配器(看看Android框架中的ArrayAdapter),并将该适配器绑定到一个ListView将是相当直接的。

+0

我实现了你的建议,但现在我得到一个错误:“期望的字符串,但是BEGIN_OBJECT”。我猜它与我的asynctask期待一个字符串并返回一个字符串的事实有关,同时我的doInBackground方法需要一个字符串并返回一个字符串给我的onPostExecute,它也期望一个字符串。我在我的POJO中使用了数组,并使用PostResponse response = new Gson()。fromJson(bufferedReader,PostResponse.class); – hyphen 2014-10-17 12:17:50

+0

顺便说一句 - 你的建议已经超级有用,所以谢谢你! – hyphen 2014-10-17 12:18:31

+0

@hyphen:你所描述的错误通常是试图将一个复杂的json对象(在'{...}'之间的东西)映射到一个java字符串上的结果。把它看作是一种类型不匹配,其中Java对象不能正确建模json。基本上,任何介于'{...}'之间的东西都应该有一个Java中的等价对象。看看周围,你会发现很多类似的问题和他们的解决方案。如果这没有帮助,也许考虑用你的进度更新问题,以便我们可以从那里继续。 – 2014-10-17 14:23:10

0
  1. 答案是yes.Response被接收作为InputSteam

  2. 保护无效onPostExecute(字符串结果) { super.onPostExecute(结果);

    Gson gson = new Gson();    
    PostResponse response = gson.fromJson(result, PostResponse.class); 
    System.out.println(result); 
    

    }

该代码段大多意味着AsyncTask该得到的网络响应,并获得字符串格式的JSON响应后,这onPostExecute将与Stringfied JSON调用。

Gson gson = new Gson(); 

Gson是Google支持的一个库,用于将android反序列化到您的类OBject中。

gson.fromJson(result, PostResponse.class); 

这种方法是真正的反序列化过程。 result是Stringfied json,第二个是要反序列化到的目标类。 这将返回一个PostResponse对象,您现在可以使用它。

+0

好的,好像我已经完成了你提到的代码的最后一行,当我将它分配给“响应”变量时,但你说我需要再次这样做?另外,我将如何访问其中一个对象中的其中一个元素?所以如果我只想要一个“cat_name”,我将如何访问它? – hyphen 2014-10-17 01:43:40

+0

使用JsonObject类。 JSONObject json = new JSONObject(string);如果你想访问指定的名称属性,只需调用json.getString(“propertyName”) – 2014-10-17 01:49:08

0

对于JSON数据(

{"expense":[{"cat_id_PK":237,"cat_name":"Name1","cat_amount":"100.00","is_recurring":0}, 
    {"cat_id_PK":238,"cat_name":"Name2","cat_amount":"200.00","is_recurring":0}, 
    {"cat_id_PK":239,"cat_name":"Name3","cat_amount":"300.00","is_recurring":0}, 
    {"cat_id_PK":240,"cat_name":"Name4","cat_amount":"400.00","is_recurring":0}], 
    "expense_rec": [{"cat_id_PK":207,"cat_name":"Name5","cat_amount":"500.00","is_recurring":1}]}), 

它包含这里有两个不同的数组,一个是“牺牲”,另一个是“expense_rec”。所以,如果你想填充这些项目清单的活动,你可以试试如下方法

protected void onPostExecute(String result) { 
    super.onPostExecute(result); 

    JSONObject jsonObject = new JSONObject(builder.toString()); 
    Log.i(TAG, "jsonObject is : " + jsonObject.toString()); 

    //this is the first array data 
    JSONArray jsonArray = jsonObject.getJSONArray("expense"); 
    Log.i(TAG, "Array length is: " + jsonArray.length()); 

    for(int i = 0; i < jsonArray.length(); i++){ 
     JSONObject jsoObj = jsonArray.getJSONObject(i); 
     String name = jsoObj.getString("cat_name"); 
     Log.i(TAG, "file name is: " + name); 
    } 

    //this is the second array data 
    jsonArray = jsonObject.getJSONArray("expense_rec"); 
    for(int i = 0; i < jsonArray.length(); i++){ 
     JSONObject jsoObj = jsonArray.getJSONObject(i); 
     String name = jsoObj.getString("cat_name"); 
     Log.i(TAG, "file name is: " + name); 
    } 
} 
1
  1. 答案是肯定的,你会得到的InputStream
  2. 响应你的第二个问题,检查了这一点 - jsonschema2pojo在为您的JSON数据创建模型时,这会很有帮助。

然后使用GSON

Gson gson = new Gson(); 
YourObj yourObj = (YourObj) gson.fromJson(result, YourObj.class); 
+0

jsonschema2pojo网站真的很有用。我没有足够的代表让你高兴,但你获得了1点良好的业力点数。谢谢! – hyphen 2014-10-20 10:34:10

+0

高兴地帮助.. :) – 2014-10-21 11:48:34