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

时间:2022-10-30 23:45:46

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

	@Override
	public 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;
	}

	@Override
	public 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 {

	@Override
	protected 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() {
			
			@Override
			public 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")
			@Override
			public 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