项目场景:
在Android系统源码里面做一个网络请求的需求,由于是系统级的App(如:Settings, SystemUI), 一些主流的第三方库(Retrofit2+Okhttp3网络请求框架,Gson 解析Json)无法直接使用。
当然呢,我们也可以在系统app中 引入第三方的aar 或 jar包去解决这个问题,但是考虑到代码解耦和功能代码的可移植性,所以尽量用系统的API去完成此需求,不依赖第三方库。
【项目需求】:通过传入应用的包名进行网络请求,来获取服务器上此APP的相关信息
解决方案:
网络请求,我们使用系统的HttpURLConnection, Json数据, 我们使用系统自带的JSONObject JSONArray 去解析,到这里真的有点返璞归真,使用元老级的API去做需求。
这也间接说明现在我们能有那么多性能高效,功能完善,封装完整的第三方库拿来直接用,是多么幸福的一件事情,也要感谢那些贡献开源代码的作者,致敬!
代码如下
1. 通过apk包名拼接URL地址,进行网络数据请求:
public class NetworkUtils {
private static final int DEFAULT_TIMEOUT = 8000;
private static final String TAG = "NetUtils";
//定义回调方法
public interface HttpCallbackListener {
//1. 封装好bean对象后,传递给调用的地方
void onFinishContentBean contentBeanObj);
//2. 发生异常时,传递报错信息
void onError(Exception e);
}
public static void getAppData(String pkgName, final HttpCallbackListener listener) {
new Thread(new Runnable() {
@Override
public void run() {
HttpURLConnection connection = null;
try {
URL url = new URL("https://www.baidu.com?packageName=" + pkgName);
connection = (HttpURLConnection) url.openConnection();
//GET请求
connection.setRequestMethod("GET");
connection.setConnectTimeout(DEFAULT_TIMEOUT);
connection.setReadTimeout(DEFAULT_TIMEOUT);
//获取数据成功
if (HttpURLConnection.HTTP_OK == connection.getResponseCode()) {
//服务器响应返回的字节流
InputStream inputStream = connection.getInputStream();
//转换成字符流
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "utf-8"));
StringBuilder response = new StringBuilder();
String line = "";
while ((line = bufferedReader.readLine()) != null) {
response.append(line);
}
//关闭io流
inputStream.close();
bufferedReader.close();
//解析并封装对象
if (null != listener) {
listener.onFinish(parseJsonString(response.toString()));
}
}
} catch (Exception e) {
//网络请求异常时回调,带回错误的信息
if (null != listener) {
listener.onError(e);
}
} finally {
if (null != connection) {
connection.disconnect();
}
}
}
}).start();
}
}
2. 封装ContentBean对象
网络请求返回数据如下图:
我们把上面的数据通过JSONObject 和 JSONArray 相关的API 解析并封装ContentBean
private ContentBean parseJsonString(String jsonData) {
ContentBean contentBean = null;
if (null != jsonData) {
try {
// 获取最外层的JSONObject对象
JSONObject object = new JSONObject(jsonData);
// 通过object对象获取code值,来判断数据状态值是否异常
String resultCode = object.getString("code");
// 开始解析
if ("ok".equals(resultCode)) {
//创建bean对象
contentBean = new ContentBean();
//这里通过 最外层的object 来获取 子JSONObject对象
JSONObject dataObj = object.getJSONObject("data");
contentBean.setCatalogName(dataObj.getString("catalogName"));
contentBean.setCompany(dataObj.getString("company"));
contentBean.setDescription(dataObj.getString("description"));
contentBean.setFullPackage(dataObj.getString("fullPackage"));
contentBean.setHash(dataObj.getString("hash"));
contentBean.setIcon(dataObj.getString("icon"));
contentBean.setId(dataObj.getInt("id"));
contentBean.setMd5(dataObj.getString("md5"));
contentBean.setName(dataObj.getString("name"));
contentBean.setPackageName(dataObj.getString("packageName"));
contentBean.setSize(dataObj.getInt("size"));
contentBean.setType(dataObj.getInt("type"));
contentBean.setUpdateTime(dataObj.getString("updateTime"));
contentBean.setVersionCode(dataObj.getInt("versionCode"));
//通过 子dataObj 来获取 子JSONArray对象
JSONArray snapObj = dataObj.getJSONArray("snapshots");
List<String> snapshots = new ArrayList<String>();
for (int i=0; i<snapObj.length(); i++) {
snapshots.add((String) snapObj.get(i));
}
contentBean.setSnapshots(snapshots);
contentBean.setFeatures(dataObj.getString("features"));
}
} catch (JSONException e) {
e.printStackTrace();
return null;
}
}
return contentBean;
}
小结:
关于用JSONObject 和 JSONArray的使用,就好像一层一层的抽丝剥茧的去拿我们需要的数据, 打个比方:“麻屋子,红帐子,里面住个白胖子”,要想获得白胖子,先得依赖于红帐子。
1. 如果要获取"子JSONObject",就需要用"父JSONObject" 调用getJSONObject(String key)
方法得到。
2. 如果要获取"子JSONArray",就需要通过最近上一层的“父JSONObject”调用 getJSONArray(String key)方法得到。