[Android]打造一个Android通用的JSON数据解析框架

来源:互联网 发布:c语言求真值表 编辑:程序博客网 时间:2024/05/23 13:31

目前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

0 0
原创粉丝点击