2011-05-06

在 Android 裡使用 HttpURLConnection 讀取遠端的 JSON 資料


在 EditText 輸入英文,按下 Enter 或翻譯 Button,程式建立 HttpURLConnection 連線 Google Translate API 取得中文意思顯示於畫面上。

XML layout 設定檔如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
    <LinearLayout 
        android:orientation="horizontal"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        >
        <EditText  
          android:hint="輸入英文"
          android:layout_width="wrap_content" 
          android:layout_height="wrap_content"
          android:layout_weight="1"
          android:singleLine="true"
          android:id="@+id/input"
          />
        <Button  
          android:layout_width="wrap_content" 
          android:layout_height="wrap_content" 
          android:layout_weight="0"
          android:text="翻譯"
          android:id="@+id/btn"
          />
    </LinearLayout>
    <TextView  
      android:layout_width="fill_parent" 
      android:layout_height="wrap_content" 
      android:id="@+id/result"
      />
</LinearLayout>
Activity 程式如下:
public class A_Json extends Activity implements OnClickListener, OnKeyListener {

    private EditText input;
    private TextView result;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        ((Button) this.findViewById(R.id.btn)).setOnClickListener(this);
        this.input = (EditText) this.findViewById(R.id.input);
        this.input.setOnKeyListener(this);
        this.result = (TextView) this.findViewById(R.id.result);
    }

    @Override
    public void onClick(View v) {
        // 按下 Button 即送出查詢
        this.translate();
    }

    @Override
    public boolean onKey(View v, int keyCode, KeyEvent event) {
        // 按下 Enter 即送出查詢
        if (keyCode == KeyEvent.KEYCODE_ENTER) {
            this.translate();
            return true;
        }
        return false;
    }

    private void translate() {
        this.result.setText(this.doTranslate());
    }

    private String doTranslate() {
        HttpURLConnection conn = null;
        try {
            if (Thread.interrupted()) {
                throw new InterruptedException();
            }
            // 略過沒有輸入或輸入空白
            String q = this.input.getText().toString();
            if (q == null) {
                return "";
            }
            q = q.trim();
            if (q.length() == 0) {
                return "";
            }
            // 建立連線
            URL url = new URL(
                    "http://ajax.googleapis.com/ajax/services/language/translate?v=1.0&langpair=en%7Czh-TW&q="
                            + q);
            conn = (HttpURLConnection) url.openConnection();
            conn.setReadTimeout(10000);
            conn.setConnectTimeout(15000);
            conn.setRequestMethod("GET");
            conn.connect();
            if (Thread.interrupted()) {
                throw new InterruptedException();
            }
            // 讀取資料
            BufferedReader reader = new BufferedReader(new InputStreamReader(
                    conn.getInputStream(), "UTF-8"));
            String jsonString1 = reader.readLine();
            reader.close();
            // 解析 json
            String jsonString = jsonString1;
            JSONObject jsonObj = new JSONObject(jsonString);
            return q
                    + " > "
                    + jsonObj.getJSONObject("responseData").opt(
                            "translatedText");
        }
        catch (Exception e) {
            return "Error: " + e.getMessage();
        }
        finally {
            if (conn != null) {
                conn.disconnect();
            }
        }
    }
}
最後在 AndroidManifest.xml 開放網路的權限:
<manifest ...>
    <uses-permission android:name="android.permission.INTERNET"/>
    ...
</manifest>

15 則留言:

  1. 若出現Error.ajax.googleapis.com
    是什麼意思呢??
    是找不到回傳值嗎??

    回覆刪除
  2. 請問是在執行那一段程式出現的?會不會是沒有設定網路權限?

    回覆刪除
  3. 若出現
    Error:Value null at responseData of type org.json.JSONObject$1 cannot be converted to JSONObject
    是什麼意思呢??

    回覆刪除
  4. 網誌管理員已經移除這則留言。

    回覆刪除
  5. 網誌管理員已經移除這則留言。

    回覆刪除
  6. 網誌管理員已經移除這則留言。

    回覆刪除
  7. 請問有什麼地方不懂嗎?討論沒問題,整包專案可能有困難,不好意思。

    回覆刪除
  8. 請問我要改善這個程式碼,它似乎無法連線,可是政府給的opendata就是這樣
    我是不是不能這樣寫
    String url = "http://data.fda.gov.tw/cacheData/35_3.json";
    謝謝

    資料來源 : http://data.fda.gov.tw/frontsite/data/DataAction.do?method=doDetail&infoId=35

    回覆刪除
    回覆
    1. 有什麼錯誤訊息嗎?

      刪除
    2. 我目前測試是可能對方的server有問題,所以換成連我這邊的檔案可以連,但是他會出現 " Error : no value for 機構狀態 ",我試過json線上編碼去編寫.json,但還是一樣說抓取不到出現亂碼
      還是我們可以email通訊討論,我的專案還有我要用的.json內容,感謝您
      我急於1/4以前要解解析出內容,並存成array 並 bundle給其他頁做應用,謝謝

      刪除
  9. 作者已經移除這則留言。

    回覆刪除
  10. 您好,我也有一個Android去讀取JSON的問題要向您請教,也就是從Chrome上看一個Opendata的JSON,可以確定JSON資料是完整的,但透過 Android 去讀取時,資料會不完成,得到的資料最後出現null,請問這大概會是什麼問題?我在InputStreamReader處也有將資料轉成 UTF-8,但還是無法解決,以下是我取資料的網址,再請您協助解答,感恩

    http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20geo.placefinder%20where%20text=%27嘉義市%27&format=json

    這是我取到資料的結果:{"query":{"count":0,"created":"2015-01-05T14:38:49Z","lang":"en-US","results":null}}

    回覆刪除
    回覆
    1. 我試過你給的網址,另外起 thread 是可以抓到資料的,我這篇筆記直接在 UI Thread 裡連網抓資料是很不好的實做方式,建議要連網抓資料一定要另外起 thread,不管是用 Java Thread 或者 Android Task 都行。

      刪除
  11. 請問版主.若傳回Error:null 是代表哪種問題?目前判斷是程式碼conn.connect();有關..不過還是無法找到解決的方向..希望能協助解答.感謝^_^ PS:使用實機測試

    回覆刪除
    回覆
    1. 剛剛爬文找到方法.如同上述的thread有關
      加入StrictMode.ThreadPolicy.Builder().detectDiskReads().detectDiskWrites().detectNetwork().penaltyLog().build());
      就解決了^_^
      引用網址 http://www.chengxuyuans.com/Android/65735.html

      刪除