2013-11-22 21 views
0

我試圖製作一個從Android上的url獲取數據的應用程序。我注意到JSON文件是不同的。他們中的一些人從一個陣式名稱開始,而另一些則沒有。那些具有數組名稱like this哪些「用戶」是數組名稱在我的應用程序中工作,但那些沒有任何數組名稱不起作用。 For example this如何在JSON文件沒有任何對象時創建數組,並且只有對象

這是我儘量讓數組對象的代碼,但它不會爲第二JSON文件工作,因爲它沒有找到數組名稱:

//URL to get JSON Array 
private static String url = "http://api.worldbank.org/countries/ir?format=json"; 

//JSON Node Names 
private static final String TAG_USER = "user"; 
private static final String TAG_ID = "id"; 
private static final String TAG_NAME = "name"; 
private static final String TAG_EMAIL = "email"; 

JSONArray user = null; 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 

    setContentView(R.layout.activity_main); 

    // Creating new JSON Parser 
    JSONParser jParser = new JSONParser(); 

    // Getting JSON from URL 
    JSONObject json = jParser.getJSONFromUrl(url); 

    try { 
     // Getting JSON Array 
     user = json.getJSONArray(TAG_USER); 
     JSONObject c = user.getJSONObject(0); 

     // Storing JSON item in a Variable 
     String id = c.getString(TAG_ID); 
     String name = c.getString(TAG_NAME); 
     String email = c.getString(TAG_EMAIL); 

     //Importing TextView 
     final TextView uid = (TextView)findViewById(R.id.uid); 
     final TextView name1 = (TextView)findViewById(R.id.name); 
     final TextView email1 = (TextView)findViewById(R.id.email); 

     //Set JSON Data in TextView 
     uid.setText(id); 
     name1.setText(name); 
     email1.setText(email); 

} catch (JSONException e) { 
    e.printStackTrace(); 
} 

} 

所以這個例子是第一個JSON部分。你能告訴我如何有類似的代碼,但第二個JSON文件嗎?

+0

您對第二個文件中的哪些信息感興趣? – Octoshape

+0

@Octoshape任何。我只想學習處理這種有數組而不是對象的文件。我會得到像id,name,region,iso2Code – user2977338

+0

這樣的數據你使用JSONParser的learn2crack庫還是你自己寫了一個? – Octoshape

回答

2

所以首先你不許百姓網東西主線程上,因爲這些東西往往會需要很長時間(如果服務器沒有響應,或者接觸不良,或者您正試圖獲取該文件是大),如果在主線程上完成,它將阻塞手機上的應用程序。如果您的應用無法響應太久,它將自動從Android操作系統中終止。爲了避免這種情況,你需要使用AsyncTasks。這些任務可以在後臺工作,而您的主線程仍可以響應用戶輸入。

你可以閱讀更多關於AsyncTasks here

[編輯] 所以要回答你的問題你的意見:你之所以得到NetworkOnMainThreadException是因爲你在你的主線程中調用jParser.getJSONFromUrl(url);(一個您通常執行的代碼)。不允許這樣做的原因是因爲在方法getJSONFromUrl()中,您發出HTTP請求,並且必須等待來自給定URL的響應。這可能需要很長時間,正如我上面所解釋的那樣,並會在已解釋的後果的情況下阻止您的電話應用。現在解決這個問題,你需要做這樣的事情:

之前(壞):

protected void onCreate(Bundle savedInstanceState) { 

super.onCreate(savedInstanceState); 

setContentView(R.layout.activity_main); 

// Creating new JSON Parser 
JSONParser jParser = new JSONParser(); 

// Getting JSON from URL 
JSONObject json = jParser.getJSONFromUrl(url); 

// get the data from your JSONObject 

} 

更好:

protected void onCreate(Bundle savedInstanceState) { 

super.onCreate(savedInstanceState); 

setContentView(R.layout.activity_main); 

// Getting JSON from URL 
new JsonRequest().execute(url); 

} 

private class JsonRequest extends AsyncTask<String, Void, JSONObject> 
// I will talk about the parameters to AsyncTask below 
    @Override 
    protected JSONObject doInBackground(String... urls) { 
     // Creating new JSON Parser 
     JSONParser jParser = new JSONParser(); 

     // Getting JSON from URL 
     JSONObject json = jParser.getJSONFromUrl(url); 

     return json; 
    } 


    @Override 
    protected void onPostExecute(JSONObject result) { 

     // Get the array 
     JSONArray array = result.getJSONArray("data"); 

     // Display the data 
     // Import textviews 
     // and so on.. 
    } 

現在談談參數AsyncTask

  1. 此類型是給定的參數的類型doInBackground
  2. 這種類型用於顯示進度條,例如,如果你下載了很多東西,你可以重寫一個名爲onProgressUpdate的函數,並且可以顯示已經在你的應用上下載了多少東西,所以用戶知道發生了某些事情。
  3. 這種類型是doInBackground將返回類型和onPostExecute具有作爲參數。

這樣,您的主線程將繼續運行,用戶不會注意到有一個事件在後臺進行下載,因爲它是一個正在運行的單獨任務。我希望這很明顯,如果不是,只是留下另一個評論,我會解釋更多。:)

[\編輯]

然後第二個問題是,從learn2crack的JSONParser無法解析JSONArrays,換句話說,功能getJSONFromUrl()只是試圖從它創建從得到StringJSONObject給定的網址。

Theres基本上有幾種方法可以解決這個問題,我做了一些小技巧(它包含很少的代碼,但之後需要更多時間才能獲取數據)。我添加以下行到getJSONFromUrl()方法:

if (json.startsWith("[")) { 
    // We have a JSONArray 
    try { 
     jObj = new JSONObject(); 
     jObj.put("data", new JSONArray(json)); 
    } catch (JSONException e) { 
     Log.d("JSON Parser", "Error parsing JSONArray " + e.toString()); 
    } 
    return jObj; 
} 

這兩根線應權這一部分的上方添加:

// try parse the string to a JSON object 
try { 
    jObj = new JSONObject(json); 
} catch (JSONException e) { 
    Log.e("JSON Parser", "Error parsing data " + e.toString()); 
} 

基本上你會到底是什麼了,然後就是你可以簡單地調用getJSONFromUrl()上任何網址,如果它包含JSONObject,您將獲得該對象,但如果它包含JSONArray,您將得到一個JSONObject,其中包含一個名爲data的字段,其中將包含您的JSONArray。所以,你可以做這樣的事情:

JSONObject json = jParser.getJSONFromUrl(url); 

JSONArray array = json.getJSONArray("data"); 

然後你有你的陣列(當然有嘗試捕捉包圍的JSONException)。

+0

我喜歡你的解決方案,我想更多的接口方面,所以我可以返回一個對象,而不是從getJSONFromUrl兩個對象。你的一個更短的方式:) – saiful103a

+0

感謝您的帖子。只有一個問題。我在'getJSONFromUrl'方法中添加了_if-statement_和'try {jObj ....'。但它產生了像'json'和'jObj'這樣的錯誤沒有被定義和聲明。這是爲什麼 ? – user2977338

+0

@ user2977338你可以請你在上面的問題中發佈完整的'getJSONFromUrl'方法代碼嗎? – Octoshape

2

據我所知,沒有具體的方法來告訴你是否在解析它之後獲取json數組或json對象。

我會解決這個問題的方法是從響應中查找字符串數據的起始字符。

在您的getJSONFromUrl方法中,您從響應中獲取字符串,然後開始將其解析爲JsonObject。在解析查找基於起始字符的起始字符之前,請確定您要使用JsonObject還是JsonArray。

我不確定他們是否有任何簡短的方法來解決這個問題,但你的問題是一個棘手的問題:)。許多其他的事情必須處理,因爲事實上你事先並不知道你是否會得到jsonobject或jsonarray。

以下是我已經把:

public interface JsonListener { 

    public boolean isJsonObejct(); 

} 

通過擴展的JSONObject和實現上述接口創建一個類。

import org.json.JSONException; 
import org.json.JSONObject; 

public class CustomJSONObject extends JSONObject implements JsonListener { 

public CustomJSONObject(String json) throws JSONException { 
    // TODO Auto-generated constructor stub 
    super(json); 
} 

@Override 
public boolean isJsonObejct() { 
    // TODO Auto-generated method stub 
    return true; 
} 

} 

通過擴展JSONArray並實現上述接口來創建另一個類。

import org.json.JSONArray; 
import org.json.JSONException; 

public class CustomJSONArray extends JSONArray implements JsonListener{ 

public CustomJSONArray(String json) throws JSONException { 
    // TODO Auto-generated constructor stub 
    super(json); 
} 

@Override 
public boolean isJsonObejct() { 
    // TODO Auto-generated method stub 
    return false; 
} 

} 

修改您的jsonparseclass,以便它不返回jsonobject或jsonarray,而是它將返回JsonListener類型的對象。

public class JSONParser { 

static InputStream is = null; 
static JsonListener jObj = null; 
static String json = ""; 

// constructor 
public JSONParser() { 

} 

public JsonListener getJSONFromUrl(String url) { 

    // Making HTTP request 
    try { 
     // defaultHttpClient 
     DefaultHttpClient httpClient = new DefaultHttpClient(); 
     HttpPost httpPost = new HttpPost(url); 

     HttpResponse httpResponse = httpClient.execute(httpPost); 
     HttpEntity httpEntity = httpResponse.getEntity(); 
     is = httpEntity.getContent();   

    } catch (UnsupportedEncodingException e) { 
     e.printStackTrace(); 
    } catch (ClientProtocolException e) { 
     e.printStackTrace(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 

    try { 
     BufferedReader reader = new BufferedReader(new InputStreamReader(
       is, "iso-8859-1"), 8); 
     StringBuilder sb = new StringBuilder(); 
     String line = null; 
     while ((line = reader.readLine()) != null) { 
      sb.append(line + "\n"); 
     } 
     is.close(); 
     json = sb.toString(); 
    } catch (Exception e) { 
     Log.e("Buffer Error", "Error converting result " + e.toString()); 
    } 

    // try parse the string to a JSON object 
    try { 
     if(json.startsWith("{")){ 
      jObj = new CustomJSONObject(json); 
     }else{ 
      jObj = new CustomJSONArray(json); 
     } 

    } catch (JSONException e) { 
     Log.e("JSON Parser", "Error parsing data " + e.toString()); 
    } 

    // return JSON String 
    return jObj; 

} 
} 

現在調整你的代碼使用這些:

// Creating new JSON Parser 
      JSONParser jParser = new JSONParser(); 

      // Getting JSON from URL 
      JsonListener json = jParser.getJSONFromUrl(url); 
      if(json.isJsonObejct()){ 
       Log.i("Got","JsonObject "+((CustomJSONObject)json).toString()); 
      }else{ 
       Log.i("Got","JsonArray "+((CustomJSONArray)json).toString()); 
      } 

希望你會從中得到一些見解。

+0

很好的使用接口。喜歡這個主意! – Octoshape

+0

感謝您的信息。但它沒有奏效。只是幾個問題,以確保我做得正確。我應該在哪裏添加我的JSONListener?我將它添加到Main_Activity的末尾。也應該刪除這條線? 'value = json.getJSONArray(VALUE);' – user2977338

+0

JSONListener將是一個單獨的文件。至於從json獲取數據,你必須使用((CustomJSONObject)json).get [你需要的數據類型]或((CustomJSONArray)json).get [你需要的數據類型]。您將在文檔中找到所有獲得者。我認爲如果你使用@Octoshape解決方案會更好,因爲就你必須編寫的代碼而言,它比我的要輕得多。但要知道如何在這種情況下利用接口,你可以使用這個。 :) – saiful103a