前言
在Android项目开发中,网络请求模块可以说是很重要的一部分(除非开发的是单机app)。所以除了自行研发一套网络请求框架之外,我相信大部分情况下很多开发者都是选择一款合适的开源的网络请求框架吧。
此文并不是比较几款开源的网络请求框架的优缺点,想了解的可以自行百度或Google吧。
而我在开发过程中,选择的是现在比较流行的,square公司开源的OkHttp网络请求框架,强大而高效!然后再结合MVP架构模式进行项目开发,使得项目开发中的代码更加优雅,职责层次更加分明!(备注:结合的MVP架构模式,在我之前发表的一篇文章中讲解过,感兴趣的话,可以点击这里去了解或者指点下通过代码封装搭建合适的MVP开发架构模式)
如果你还不熟悉OkHttp框架的使用,可以点击这里OkHttp - Square Open Source!
接下来,大致谈谈我怎样是基于OkHttp框架进行代码封装吧
网络请求回调接口
public interface NetworkRequestListener {
/**
* 网络请求前回调,进行加载框的展示
*/
void onRequestBefore();
/**
* 网络请求成功后回调,进行数据的处理和展示
* @param object
*/
void onRequestSuccess(Object object);
/**
* 网络请求失败后回调,提示请求失败信息
* @param msg
*/
void onRequestFail(String msg);
/**
* 网络请求完成后回调,关闭加载框
*/
void onRequestComplete();
}
网络请求处理对象,实例化网络请求回调接口和需要用到的一些变量
public class NetworkExecutor {
public NetworkRequestListener mListener = null;
//将json转换为实体对象
public Class<?> mClass = null;
//下载文件保存的路径
public String filePath = null;
public NetworkExecutor(NetworkRequestListener mListener) {
this.mListener = mListener;
}
public NetworkExecutor(NetworkRequestListener mListener, Class<?> mClass) {
this.mListener = mListener;
this.mClass = mClass;
}
public NetworkExecutor(NetworkRequestListener mListener, String filePath) {
this.mListener = mListener;
this.filePath = filePath;
}
}
网络请求核心类,负责创建各种请求类型,如get请求,post请求,文件上传等。
public class CoreRequest {
private static final MediaType FILE_TYPE = MediaType.parse("application/octet-stream");
/**
* get请求
* @param url
* @param params
* @return
*/
public static Request doGetRequest(String url, RequestParams params) {
StringBuilder sb = new StringBuilder(url).append("?");
if (params != null) {
for (Map.Entry<String, String> entry : params.stringParams.entrySet()) {
sb.append(entry.getKey())
.append("=")
.append(entry.getValue())
.append("&");
}
}
Logger.d("URL = " + sb.substring(0, sb.length() - 1));
Request request = new Request.Builder()
.get()
.url(sb.substring(0, sb.length() - 1))
.build();
return request;
}
/**
* post请求
* @param url
* @param params
* @return
*/
public static Request doPostRequest(String url, RequestParams params) {
FormBody.Builder builder = new FormBody.Builder();
if (params != null) {
for (Map.Entry<String, String> entry : params.stringParams.entrySet()) {
builder.add(entry.getKey(), entry.getValue());
}
}
Logger.d("URL = " + url);
FormBody body = builder.build();
Request request = new Request.Builder()
.post(body)
.url(url)
.build();
return request;
}
/**
* 上传文件请求
* @param url
* @param params
* @return
*/
public static Request uploadFileRequest(String url, RequestParams params) {
MultipartBody.Builder builder = new MultipartBody.Builder();
builder.setType(FILE_TYPE);
if (params != null) {
for (Map.Entry<String, Object> entry : params.objectParams.entrySet()) {
if (entry.getValue() instanceof File) {
builder.addPart(MultipartBody.Part.createFormData(
entry.getKey(),
null,
RequestBody.create(FILE_TYPE, (File) entry.getValue())
));
} else if (entry.getValue() instanceof String) {
builder.addFormDataPart(entry.getKey(), String.valueOf(entry.getValue()));
}
}
}
Logger.d("URL = " + url);
RequestBody body = builder.build();
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
return request;
}
}
响应和处理网络请求后服务器返回的JSON字段
public class CoreJsonResponse implements Callback {
private static final String RESULT_CODE = "status";
private static final String RESULT_MSG = "message";
private static final String RESULT_CODE_VALUE = "1";
private Class<?> mClass;
private Handler mHandler;
private Gson gson = new Gson();
private NetworkRequestListener mListener;
public CoreJsonResponse(NetworkExecutor networkExecutor) {
this.mClass = networkExecutor.mClass;
this.mListener = networkExecutor.mListener;
this.mHandler = new Handler(Looper.getMainLooper());//切换回主线程
}
@Override
public void onFailure(Call call, final IOException e) {
mHandler.post(new Runnable() {
@Override
public void run() {
Logger.e(e, "接口请求失败");
mListener.onRequestFail("网络异常");
mListener.onRequestComplete();
}
});
}
@Override
public void onResponse(Call call, Response response) throws IOException {
final String result = response.body().string();
mHandler.post(new Runnable() {
@Override
public void run() {
handleResponse(result);
}
});
}
/**
* 处理服务器返回的响应
* @param result
*/
private void handleResponse(String result) {
if (result == null && result.equals("")) {
mListener.onRequestFail("网络异常");
mListener.onRequestComplete();
return;
}
Logger.json(result);
try {
JSONObject jsonObject = new JSONObject(result);
if (jsonObject.has(RESULT_CODE)) {
if (jsonObject.optString(RESULT_CODE).equals(RESULT_CODE_VALUE)) {
if (mClass == null) {
//直接返回json字段
mListener.onRequestSuccess(jsonObject);
} else {
//将json转换为实体对象
Object object = gson.fromJson(jsonObject.toString(), mClass);
if (object == null) {
mListener.onRequestFail("json解析失败");
} else {
//返回实体对象
mListener.onRequestSuccess(object);
}
}
} else {
mListener.onRequestFail(jsonObject.optString(RESULT_MSG));
}
} else {
Logger.e("JSON字段中没有对应的验证码");
}
} catch (JSONException e) {
e.printStackTrace();
}
mListener.onRequestComplete();
}
}
需要说明下,代码中的RESULT_CODE、RESULT_MSG、RESULT_CODE_VALUE的值需要和负责服务器端的人员一起制定好,因为每个公司开发的规则或许都不一样的。
网络请求的客户端
public class NetworkRequestClient {
private static NetworkRequestClient instance;
private OkHttpClient mOkHttpClient;
private static final int TIME_OUT = 10;
private NetworkRequestClient(){
OkHttpClient.Builder builder = new OkHttpClient.Builder();
//支持Https
builder.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
builder.connectTimeout(TIME_OUT, TimeUnit.SECONDS);
// builder.readTimeout(TIME_OUT, TimeUnit.SECONDS);
// builder.writeTimeout(TIME_OUT, TimeUnit.SECONDS);
mOkHttpClient = builder.build();
}
public static NetworkRequestClient getInstance(){
if (instance == null) {
synchronized (NetworkRequestClient.class) {
if (instance == null) {
instance = new NetworkRequestClient();
}
}
}
return instance;
}
/**
* 发送请求
* @param request
* @param executor
*/
public void sendRequest(Request request, NetworkExecutor executor) {
Call call = mOkHttpClient.newCall(request);
executor.mListener.onRequestBefore();
call.enqueue(new CoreJsonResponse(executor));
}
/**
* 文件下载
* @param request
* @param executor
*/
public void downloadFile(Request request, NetworkExecutor executor) {
Call call = mOkHttpClient.newCall(request);
executor.mListener.onRequestBefore();
call.enqueue(new CoreFileResponse(executor));
}
}
结合MVP架构模式使用
在MVP架构中,model层负责获取数据,所以我在BaseModel类中,创建了NetworkRequestClient的单例对象,然后再创建NetworkExecutor对象,实现NetworkRequestListener中的接口。(如果对下面的代码感到疑惑,可以看回之前我发表的一遍文章通过代码封装搭建合适的MVP开发架构模式)
public class BaseModel {
private BaseRequestCallBack callBack;
public NetworkRequestClient httpClient;
public BaseModel(BaseRequestCallBack callBack) {
this.callBack = callBack;
httpClient = NetworkRequestClient.getInstance();
}
public NetworkExecutor getExecutor(Class<?> mClass) {
NetworkExecutor networkExecutor = new NetworkExecutor(new NetworkRequestListener() {
@Override
public void onRequestBefore() {
callBack.RequestBefore();
}
@Override
public void onRequestSuccess(Object object) {
callBack.RequestSuccess(object);
}
@Override
public void onRequestFail(String msg) {
callBack.RequestFail(msg);
}
@Override
public void onRequestComplete() {
callBack.RequestComplete();
}
}, mClass);
return networkExecutor;
}
}
代码已经上传到了我的GithubAndroidCoreLib。
总结
因为文中的贴上的代码有点多,框架使用的demo代码就不贴上了,感兴趣的可以到我的GitHub上的这里查看HomeActivity的具体操作方法。还有在通过代码封装的框架中,还有关于文件下载的请求,可以查看这里CoreFileResponse这个类,写法跟上文提到的CoreJsonResponse相似。
最后,小弟不才,还望多多指教!
网友评论