讀取並解析JSON資料
當Android應用程式連線到網路上的服務讀取資料時,並不像先前的登入範例讀取一個字元這麼簡單,在實務上,讀取更多的文字資料如網頁原始碼、XML或JSON格式等,與伺服器連線後使用的通訊協定大都是網頁HTTP協定。
使用Java語言讀取網路HTTP協定的資料大都使用java.io.BufferedReader類別,再以readLine方法在迴圈中收集所有資料,這些設計目的都是取得一個網址的連線,若能用更簡短、有效率的方式能快速取得資料的字串,再進行解析、處理,能夠加快開發速度。
本篇先使用一般的方式取得網址回應的資料,資料為目前的主流JSON格式,先使用內建的JSON.org類別庫解析資料後,在下一篇文章,再更換使用第三方函式庫Gson與Jackson進行資料的解析並使用Material Design實感設計所推出的新版清單元件RecyclerView類別,以清單的方式展示已取得的資料。
讀取JSON資料
JSON資料格式是一種輕量級的資料交換格式,以文字為基礎、易於閱讀,全名為「JavaScript Object Notation」,它原是在Javascript中表示資料的一種格式,但目前大量使用在各類程式語言中,用來表示資料或提供資料的格式。
請使用瀏覽器開啟以下網址進行測試。
網址: http://atm201605.appspot.com/h
這是一個JSON格式的測試網址,模擬一個伺服器提供交易資料明細,有五筆交易資料。
- JSON陣列
用來表示多筆資料,以程式語言的陣列來看,它含有一筆以上的資料,資料間用逗號分隔,並以中括號集合多筆資料成為一個陣列,如下:
[物件1, 物件2, 物件3, … ]- JSON物件
用以表示一筆資料,資料中的每個欄位名稱以冒號表示它的值,並以大括號集合所有欄位成為一個物件,如下:
{欄位名稱:欄位值 , 欄位名稱:欄位值 , … }
以下是一筆交易JSON物件的範例:
{“account”:”jack”,”date”:”20160501″,”amount”:1500,”type”:0}
資料的意義如下:
欄位名稱 | 值 | 說明 |
account | jack | 帳號名稱 |
date | 20150501 | 交易日期 |
amount | 1500 | 交易金額 |
type | 0 | 交易類型 |
取得伺服端傳來回應
使用AsyncTask類別設計HTTP連線工作,讀取完成後回傳字串結果,在TransActivity內設計一內部類別TransTask,並繼承AsyncTask,在doInBackground設計連線並讀取伺服器傳來回應的所有字串,程式碼如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | package com.tom.atm; import android.os.AsyncTask; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.MalformedURLException; import java.net.URL; public class TransActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_trans); new TransTask() .execute("http://atm201605.appspot.com/h"); } class TransTask extends AsyncTask<String, Void, String>{ @Override protected String doInBackground(String... params) { StringBuilder sb = new StringBuilder(); try { URL url = new URL(params[0]); BufferedReader in = new BufferedReader( new InputStreamReader(url.openStream())); String line = in.readLine(); while(line!=null){ Log.d("HTTP", line); sb.append(line); line = in.readLine(); } } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return sb.toString(); } } } |
接下來請再覆寫TransTask內的onPostExecute方法,接收doInBackground最後return回值的字串,進行後續解析工作,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public class TransActivity extends AppCompatActivity { ... class TransTask extends AsyncTask<String, Void, String>{ ... @Override protected void onPostExecute(String s) { super.onPostExecute(s); Log.d("JSON", s); parseJSON(s); } } private void parseJSON(String s) { } } |
第5-10行,覆寫的onPostExecute方法,在doInBackground方法執行完成後自動執行的方法。
第8行,使用Log類別印出除錯訊息
第9行,呼叫自行設計的parseJSON方法,並傳入從網頁讀取的字串資料。
第13-14行,自行設計的方法,為了解析JSON資料而建立。
以上是連線網路並讀取資料的設計過程,必須設計AsyncTask類別、實作方法、建立網路連線、讀取並收集資料等,這樣的任務實在繁複。如果應用程式中經常需要這類的工作設計時,有無方法可以簡化呢?
第三方類別庫
由於開放原始碼的盛行,有許多專案都提供這類的函式庫,可加快開發速度,簡化繁雜的工作。例如網路連線常用的okHttp、Volley,JSON解析使用Gson或Jackson類別庫。
Gradle設定檔
Android Studio的每一個模組(Module)可以擁有自己的設定檔,而一個專案可以擁有多個模組,設計Android應用程式時就是自動產生個名為「app」的模組。設定檔檔名統一為「build.gradle」,它是一個使用Groovy語法的純文字檔案,記錄這個模組如何編譯、包裝、執行等工作,若模組使用到外來的函式庫也在此檔中加入。一般來說,我們通常只需要修改app模組的build.gradle,如下圖:
在模組中使用JDK與Android SDK以外的函式庫前,必須在Gradle的設定檔「build.gradle」中設定,請展開專案區的「Gradle Scripts」,點擊開啟「build.gradle(Module:app)」,檔案如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | apply plugin: 'com.android.application' android { compileSdkVersion 23 buildToolsVersion "24.0.0 rc2" defaultConfig { applicationId "com.tom.atm" minSdkVersion 15 targetSdkVersion 23 versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:23.3.0' compile 'com.android.support:design:23.3.0' } |
分別就三個區塊說明如下:
老師您好:
想請教老師,如果該URL需要登入的動作
一般網頁URL輸入方式為http://admin:admin@192.xxx.xxx.xx…
而admin就是帳號與密碼,
那如果要使用這個api,是否URL也能這樣設定呢?
還是需要其他寫法呢?謝謝.
可使用com.squareup.okhttp.Authenticator
以下這則的回應中有範例:
http://stackoverflow.com/questions/22490057/android-okhttp-with-basic-authentication
您好
請問若要強制中斷請求的話
該如何實作呢
老師您好,
最近看到Hahow上面有您的課程非常想要購買,
可是我現在比較有問題的是關於用Web API讀取JSON這方面的問題
尤其是在JSON Get Post上面的選擇有許多的疑問想上課
請問課程裡面會有講解嗎?
感謝您的回答!
hahow的Android APP高效入門線上課程中,JSON讀取是以GET方式,也無編碼問題(純英文UTF-8),如果有這類需求,可以在學習後在hahow課程單元中留言討論,如果太繁雜無法用寫的,我會利用粉絲專頁的直播機會實作,請追蹤加搶先看 🙂
Android APP高效入門線上課程: https://hahow.in/cr/androidx
FB粉專: https://www.facebook.com/Androidpa/