2014-10-17 52 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