[Android]打造一個Android通用的JSON資料解析架構

來源:互聯網
上載者:User

目前Android和ios應用與網路互動使用得最多的是json資料協議,json輕快的特點十分適合移動平台,因此已逐漸取代了xml,下面來看兩個常見的json格式:

{"code":"10000","message":"Login ok","result":{"User":{"id":1,"name":"james","sign":"just do it"}}}
{"code":"10000","message":"Get weibo list ok","result":{"Weibo.list":[{"id":2,"author":"zhuge","content":"weibo content 2"},{"id":1,"author":"zhuge","content":"weibo content 1"}]}}

兩種格式的結構一致,唯一不同的是result欄位,前者result欄位中是一個JSONObject,常用於返回一些普通的資訊,後者是JSONArray,長用與返回一些列表資料。

首先先來說最常規最普通的解析方式,定義兩個實體,一個叫User,一個叫Weibo,請一目十行地掃過。

package com.zhuge.jsonparse;import java.util.ArrayList;import java.util.HashMap;import org.json.JSONArray;import org.json.JSONException;import org.json.JSONObject;public class User extends BaseModel {private String id;private String name;private String sign;public String getId() {return id;}public void setId(String id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getSign() {return sign;}public void setSign(String sign) {this.sign = sign;}@Overridepublic String toString() {return "User [id=" + id + ", name=" + name + ", sign=" + sign + "]";}public static HashMap<String, Object> parseUserInfo(String jsonStr) {HashMap<String, Object> result = new HashMap<String, Object>();User user = new User();try {JSONObject apiJson = new JSONObject(jsonStr);result.put("code", apiJson.getString("code"));result.put("message", apiJson.getString("message"));JSONObject resultJson = apiJson.getJSONObject("result").getJSONObject("User");user.setId(resultJson.getString("id"));user.setName(resultJson.getString("name"));user.setSign(resultJson.getString("sign"));result.put("result", user);} catch (JSONException e) {e.printStackTrace();}return result;}}
package com.zhuge.jsonparse;import java.util.ArrayList;import java.util.HashMap;import org.json.JSONArray;import org.json.JSONException;import org.json.JSONObject;public class Weibo extends BaseModel {private String id;private String author;private String content;public String getId() {return id;}public void setId(String id) {this.id = id;}public String getAuthor() {return author;}public void setAuthor(String author) {this.author = author;}public String getContent() {return content;}public void setContent(String content) {this.content = content;}@Overridepublic String toString() {return "Weibo [id=" + id + ", author=" + author + ", content="+ content + "]";}public static HashMap<String, Object> parseWeiboList(String jsonStr) {HashMap<String, Object> result = new HashMap<String, Object>();ArrayList<Weibo> lstWeibo = new ArrayList<Weibo>();try {JSONObject apiJson = new JSONObject(jsonStr);result.put("code", apiJson.getString("code"));result.put("message", apiJson.getString("message"));JSONObject resultJson = apiJson.getJSONObject("result");JSONArray resultArray = resultJson.getJSONArray("Weibo.list");for (int i = 0; i < resultArray.length(); i++) {JSONObject weiboJson = resultArray.getJSONObject(i);Weibo weibo = new Weibo();weibo.setId(weiboJson.getString("id"));weibo.setAuthor(weiboJson.getString("author"));weibo.setContent(weiboJson.getString("content"));lstWeibo.add(weibo);}result.put("result", lstWeibo);} catch (JSONException e) {e.printStackTrace();}return result;}}

兩個實體都繼承自BaseModel,而BaseModel只是個空類,裡面什麼也沒有定義,雖然是個空類,但也必須繼承,為我們後面的通用性做準備。User和Weibo兩個實體類中分別定義了三個簡單的屬性,然後是一些自動產生的get和set方法,最後就是對json資料解析與資料封裝的靜態方法。這種解析方式通用性不強,每定義一個實體類都要單獨針對其做解析,這顯然不是我們想要的方式,作為一名程式猿不會“偷懶”那就只能加班。

好了,下面我們來看看本文的重點,打造一個通用的json資料解析架構,只要是按照上面的json協議定義的資料格式(當然你也可以用自己的格式,修改相應代碼就好了),簡簡單單搞定所有的實體類解析:

package com.zhuge.jsonparse;import java.lang.reflect.Field;import java.util.ArrayList;import java.util.HashMap;import java.util.Iterator;import java.util.Map;import org.json.JSONArray;import org.json.JSONException;import org.json.JSONObject;import android.util.Log;/** * JSON通用解析架構 * @author zhugeheng * */public class ApiResult {private String code;private String message;private Map<String, BaseModel> resultMap;private Map<String, ArrayList<? extends BaseModel>> resultList;public ApiResult () {this.resultMap = new HashMap<String, BaseModel>();this.resultList = new HashMap<String, ArrayList<? extends BaseModel>>();}public String getCode () {return this.code;}public void setCode (String code) {this.code = code;}public String getMessage () {return this.message;}public void setMessage (String message) {this.message = message;}/** * 擷取對象實體 * @param modelName * @return * @throws Exception */public Object getModel (String modelName) throws Exception {Object model = this.resultMap.get(modelName);if (model == null) {throw new Exception("Result map is empty");}return model;}/** * 擷取對象實體列表 * @param modelName * @return * @throws Exception */public ArrayList<? extends BaseModel> getModelList (String modelName) throws Exception {ArrayList<? extends BaseModel> modelList = this.resultList.get(modelName);if (modelList == null || modelList.size() == 0) {throw new Exception("Result list is empty");}return modelList;}/** * 擷取ApiResult實體 * @param jsonStr * @return * @throws Exception */public ApiResult getApiResult(String jsonStr) throws Exception {ApiResult apiResult = new ApiResult();JSONObject jsonObject = null;try {jsonObject = new JSONObject(jsonStr);if (jsonObject != null) {apiResult.setCode(jsonObject.getString("code"));apiResult.setMessage(jsonObject.getString("message"));apiResult.setResult(jsonObject.getString("result"));}} catch (JSONException e) {throw new Exception("Json format error");} catch (Exception e) {e.printStackTrace();}return apiResult;}/** * 解析Result欄位的內容 * @param result * @throws Exception */@SuppressWarnings("unchecked")private void setResult (String result) throws Exception {if (result.length() > 0) {JSONObject jsonObject = new JSONObject(result);Iterator<String> it = jsonObject.keys();while (it.hasNext()) {String jsonKey = it.next();String modelName = getModelName(jsonKey);//實體類所在絕對路徑(包名+類名)String modelClassName = "com.zhuge.jsonparse.model." + modelName;Log.d("ApiResult", "json key:" + jsonKey + ",model class name:" + modelClassName);//預設以Array處理JSONArray modelJsonArray = jsonObject.optJSONArray(jsonKey);if (modelJsonArray == null) {//不是Array,那麼就是一個普通的Object,如User類JSONObject modelJsonObject = jsonObject.optJSONObject(jsonKey);if (modelJsonObject == null) {throw new Exception("json result is invalid");}//將JSONObject轉換為Model類並儲存結果到Map中this.resultMap.put(modelName, json2model(modelClassName, modelJsonObject));} else {//是Array,如Weibo類ArrayList<BaseModel> modelList = new ArrayList<BaseModel>();for (int i = 0; i < modelJsonArray.length(); i++) {JSONObject modelJsonObject = modelJsonArray.optJSONObject(i);//將JSONObject轉換為Model類並添加到List中modelList.add(json2model(modelClassName, modelJsonObject));}//添加結果清單到Map中this.resultList.put(modelName, modelList);}}}}/** * 將JSON對象轉換為實體物件 * @param modelClassName 實體類所在絕對路徑(包名+類名),大小寫敏感 * @param modelJsonObject “result”欄位中的內容 * @return * @throws Exception */@SuppressWarnings("unchecked")private BaseModel json2model (String modelClassName, JSONObject modelJsonObject) throws Exception  {BaseModel modelObj = (BaseModel) Class.forName(modelClassName).newInstance();//擷取實體類Class<? extends BaseModel> modelClass = modelObj.getClass();//擷取該實體類所有的屬性集合Iterator<String> it = modelJsonObject.keys();while (it.hasNext()) {//屬性名稱String varField = it.next();//解析屬性值String varValue = modelJsonObject.getString(varField);Log.d("ApiResult", "field:" + varField + "  value:" + varValue);//產生屬性封裝對象Field field = modelClass.getDeclaredField(varField);//設定可訪問私人屬性field.setAccessible(true);//將modelObj對象的field屬性的值設為解析得到的值field.set(modelObj, varValue);}return modelObj;}/** * 去掉返回結果的“list” * @param str * @return */private String getModelName (String str) {String[] strArr = str.split("\\W");if (strArr.length > 0) {str = strArr[0];}return str;}}
請重點關注 setResultjson2Model方法,另外getMode方法用於擷取一個普通的實體物件如User,getModeList方法用於擷取實體物件列表如WeiboList,二者對外暴露。關鍵代碼都有詳細的注釋,比較好理解,這裡就不再囉嗦了。然後你就可以幹掉User和Weibo類中的 parseXXX 方法了,接下來看看如何調用我們的通用方法:
package com.zhuge.jsonparse;import java.io.IOException;import java.io.InputStream;import java.util.ArrayList;import android.app.Activity;import android.os.Bundle;import android.view.View;import android.view.View.OnClickListener;import android.widget.TextView;public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);final TextView tvResult = (TextView) findViewById(R.id.tv_result);findViewById(R.id.btn_obj).setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View arg0) {String jsonStr = readAssetsFile("user.json");try {//HashMap<String, Object> result = User.parseUserInfo(jsonStr);//User user = (User)result.get("result");ApiResult result = new ApiResult().getApiResult(jsonStr);User user = (User)result.getModel("User");tvResult.setText(user.toString());} catch (Exception e) {e.printStackTrace();}}});findViewById(R.id.btn_array).setOnClickListener(new OnClickListener() {@SuppressWarnings("unchecked")@Overridepublic void onClick(View arg0) {String jsonStr = readAssetsFile("weibo.json");try {//HashMap<String, Object> result = Weibo.parseWeiboList(jsonStr);//ArrayList<Weibo> lstWeibo = (ArrayList<Weibo>)result.get("result");ApiResult result = new ApiResult().getApiResult(jsonStr);ArrayList<Weibo> lstWeibo = (ArrayList<Weibo>)result.getModelList("Weibo");String str = "";for(Weibo weibo : lstWeibo) {str += weibo.toString() + "\n";}tvResult.setText(str);} catch (Exception e) {e.printStackTrace();}}});}/** * 讀取assets檔案夾中的內容(測試json字串) * @param fileName * @return */private String readAssetsFile(String fileName) {try {InputStream is = getAssets().open(fileName);int size = is.available();byte[] buffer = new byte[size];is.read(buffer);is.close();String result = new String(buffer, "UTF-8");return result;} catch (IOException e) {e.printStackTrace();return null;}}}
該Activity很簡單,有兩個Button,第一個點擊後解析User,第二個點擊後解析Weibo List,然後在TextView中將實體用toString方法列印出來。另外,一般我們的json資料都是從網路伺服器擷取的,本例為了示範方便將json檔案放在了assets檔案夾中然後直接讀取(網路擷取資料也不是本文的重點)。OK,一個通用性比較強的解析架構搞定了,然後你就可以跟解析json資料這種體力活say goodbye了。

尊重原創,轉載請註明出處:http://blog.csdn.net/zhugehengheng/article/details/45250553

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.