上一篇文章重点介绍了如何优化现有的网络框架,本篇文章重点分析,在此基础上一步步打造网络请求框架——细节优化(二),如何进行功能上的扩展,让框架的适应性更强。
上一篇文章末尾提到,网络请求取消的功能还没有,那么,今天就把这个功能分析一下并且做出来,再看看还有没有别的方面的扩展。
关于网络请求取消,大多数情况下是我们的Acticity关闭了以后,而后台网络请求还在执行,此时最好将当前的网络请求取消(因为页面已经关闭,请求实际上没有意义了),那具体操作就是在onDestory()中操作当前线程池正在处理的任务,并且将他取消。
在RequestTask中加入部分代码:
public class RequestTask implements Runnable {
private static final String TAG = RequestTask.class.getSimpleName();
private String url;
private Map<String,String> params;
private Map<String,String> headers;
private HttpMethod httpMethod;
private JsonCallback mJsonCallback;
private Context mContext;
private static InternalHandler sHandler;
private final AtomicBoolean mCancelled = new AtomicBoolean();
private boolean isCompleted;
public RequestTask(CommonRequest request) {
this.url = request.getUrl();
this.params = request.getParams();
this.headers = request.getHeaders();
this.httpMethod = request.getHttpMethod();
this.mJsonCallback = request.getJsonCallback();
this.mContext = request.getContext();
}
public boolean isCompleted() {
return isCompleted;
}
public void execute() {
CoreExecutorService.getExecutorService().submit(this);
}
public final void cancel() {
mCancelled.set(true);
CoreExecutorService.cancel(this);
}
public boolean isCancelled() {
return mCancelled.get();
}
@Override
public void run() {
if (isCancelled()) {
onFailure(new HttpException(HttpException.ErrorType.CANCEL, "the request has been cancelled"));
LogUtils.e(TAG, "the request has been cancelled");
return;
}
if (!NetWorkUtil.isConnect(mContext)) {
//断网处理
onFailure(new HttpException(HttpException.ErrorType.IO, "请检查网络连接是否正常"));
return;
}
Response response;
String json;
if (httpMethod == HttpMethod.GET) {
if (headers != null && headers.size() > 0) {
response = HttpUtil.get(url, headers);
} else {
response = HttpUtil.get(url);
}
} else if (httpMethod == HttpMethod.POST) {
response = HttpUtil.post(url, params, headers);
} else if (httpMethod == HttpMethod.PUT) {
response = HttpUtil.put(url, params);
} else {
response = HttpUtil.delete(url, params);
}
try {
if (response != null) {
if (response.body() != null) {
json = response.body().string();
if (!TextUtils.isEmpty(json)) {
LogUtils.i(TAG, json);
JSONObject jsonObject = new JSONObject(json);
if (jsonObject.has("code")) {
int code = jsonObject.optInt("code");
String message = jsonObject.optString("msg");
String type = jsonObject.optString("type");
String data = jsonObject.optString("data");
LogUtils.i(TAG, "需要解析的数据 :" + data);
if (code == 1) {
Object o = mJsonCallback.bindData(data);
onSuccess(o);
isCompleted = true;
} else {
onFailure(new HttpException(code, message));
}
} else {
onFailure(new HttpException(HttpException.ErrorType.JSON, "json error"));
}
} else {
//Json为空
onFailure(new HttpException(HttpException.ErrorType.SERVER, "json empty"));
return;
}
}
}
} catch(Exception e){
LogUtils.e(TAG, "error---" + e.toString());
e.printStackTrace();
onFailure(e);
}
}
private void onFailure(final Exception e) {
getHandler().post(new Runnable() {
@Override
public void run() {
mJsonCallback.onFailure(e);
}
});
}
private void onSuccess(final Object o) {
getHandler().post(new Runnable() {
@Override
public void run() {
mJsonCallback.onSuccess(o);
}
});
}
private static class InternalHandler extends Handler {
InternalHandler() {
super(Looper.getMainLooper());
}
}
private static InternalHandler getHandler() {
if (sHandler == null) {
synchronized (RequestTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler();
}
}
}
return sHandler;
}
}
其中,cancel()方法调用到线程池中的cancel()中,将线程池中的任务删除
public static void cancel(Runnable task){
sPoolWorkQueue.remove(task);
}
接下来修改RequestManager和CommonRequest类
public class RequestManager {
private static RequestManager sRequestManager;
private ArrayMap<String, ArrayList<RequestTask>> mExecutedTask;
private RequestManager(){
mExecutedTask = new ArrayMap<>();
}
public static RequestManager getRequestManager(){
if(sRequestManager == null){
synchronized (RequestManager.class){
if(sRequestManager == null){
sRequestManager = new RequestManager();
}
}
}
return sRequestManager;
}
public void performRequest(CommonRequest request){
RequestTask task = new RequestTask(request);
task.execute();
if(!mExecutedTask.containsKey(request.getTag())){
ArrayList<RequestTask> tasks = new ArrayList<>();
tasks.add(task);
mExecutedTask.put(request.getTag(),tasks);
}else {
ArrayList<RequestTask> tasks = mExecutedTask.get(request.getTag());
if(tasks != null && tasks.size() > 0){
tasks.add(task);
}
}
}
public void cancelRequest(String tag){
if(tag == null || tag.equals("")){
return;
}
if(mExecutedTask.containsKey(tag)){
ArrayList<RequestTask> tasks = mExecutedTask.get(tag);
if(tasks != null && tasks.size() > 0){
for (RequestTask task: tasks) {
if(task != null){
if(!task.isCancelled() && !task.isCompleted()){
task.cancel();
}
}
}
}
}
}
}
public class CommonRequest {
private String mUrl;
private Map<String,String> mParams;
private Map<String,String> mHeaders;
private HttpMethod mHttpMethod;
private JsonCallback mJsonCallback;
private Context mContext;
private String mTag;
public CommonRequest(Builder builder) {
this.mUrl = builder.mUrl;
this.mParams = builder.mParams;
this.mHeaders = builder.mHeaders;
this.mHttpMethod = builder.mHttpMethod;
this.mJsonCallback = builder.mJsonCallback;
this.mContext = builder.mContext;
this.mTag = builder.mTag;
}
public String getTag() {
return mTag;
}
public Context getContext() {
return mContext;
}
public String getUrl() {
return mUrl;
}
public Map<String, String> getParams() {
return mParams;
}
public Map<String, String> getHeaders() {
return mHeaders;
}
public HttpMethod getHttpMethod() {
return mHttpMethod;
}
public JsonCallback getJsonCallback() {
return mJsonCallback;
}
public static class Builder{
private String mUrl;
private Map<String,String> mParams;
private Map<String,String> mHeaders;
private HttpMethod mHttpMethod;
private JsonCallback mJsonCallback;
private Context mContext;
private String mTag;
public Builder setTag(String tag) {
mTag = tag;
return this;
}
public Builder setContext(Context context) {
mContext = context;
return this;
}
public Builder setUrl(String url) {
mUrl = url;
return this;
}
public Builder setParams(Map<String, String> params) {
mParams = params;
return this;
}
public Builder setHeaders(Map<String, String> headers) {
mHeaders = headers;
return this;
}
public Builder setHttpMethod(HttpMethod httpMethod) {
mHttpMethod = httpMethod;
return this;
}
public Builder setJsonCallback(JsonCallback jsonCallback) {
mJsonCallback = jsonCallback;
return this;
}
public CommonRequest build(){
return new CommonRequest(this);
}
}
}
并且在Activity中的onDestory()中调用取消网络请求的方法
@Override
protected void onDestroy() {
super.onDestroy();
RequestManager.getRequestManager().cancelRequest(TAG);
}
上面的代码当中:TAG就是表示当前Activity的一个字符串,一般用MainActivity.class.getSimpleName()表示。在RequestManager中,我们使用了一个ArrayMap来存储当前的Activity标识和任务集合,即一个Tag对应一个List,如果当前Activity是一个列表页面,那就会有很多个网络请求,把这些网络任务全部保存在一个List当中,并且绑定对应的Activity,在Activity被销毁时,这些网络任务也就会被一一遍历出来取消掉,而具体取消任务的工作交给线程池去完成。
OK,这样一来取消网络请求的功能也已经完成,随着业务的不断增多,我们的框架也会随着业务不断完善,还有更多的功能等待我们去扩展。这三篇文章所介绍的网络框架我也用了好多年了,在此期间,也随着业务的更新去不断重构这个框架,功能还包括:支持多文件上传,支持文件下载 ,支持本地缓存(有的类似于新闻阅读类App可能有这样的需求:先加载之前缓存的本地数据,再从网络请求数据并更新UI),全部代码都已经上传了本人的Github——Http框架,上面有全部的介绍。