您的位置:首页 > 理论基础 > 计算机网络

网络请求工具类之OkHttp3封装(二)上(支持请求取消、异步请求的线程切换)

2016-06-24 15:05 429 查看
上一篇封装的已经满足一些网络请求的基本场景,但没有将网络请求与Activity/Fragment的生命周期进行绑定,导致切换页面时没有及时释放网络请求的相关资源;其次OkHttp3的异步请求结束后的回调方法是在子线程中,若要进行UI操作就得采用 runOnUiThread
方法进一步包裹,程序显的很笨拙,总之用起来不是很爽,那这一篇就对上面两个方面来进行优化。

优化任务:

1、网络请求与Activity/Fragment的生命周期进行绑定,做到Activity/Fragment销毁时,与其绑定的网络请求全部取消以释放资源

2、异步请求采用UI线程回调方式

对于任务1,实现比较简单,采用Map集合保存每次网络请求Call,Map的键为Activity/Fragment,值采用List集合保存该页面下所有的Call,考虑到多线程情况的复杂性和不可预见性,这里采用了并发包下的ConcurrentHashMap


/**
* 请求集合: key=Activity value=Call集合
*/
private static Map<Class<?>,List<Call>> callsMap = new ConcurrentHashMap<Class<?>,List<Call>>();

Activity/Fragment中直接进行网络请求,代码如下:

private void doHttpAsync(){
HttpInfo info = HttpInfo.Builder().setUrl(url).build(this);
OkHttpUtil.Builder()
.setCacheLevel(OkHttpUtil.CacheLevel.FIRST_LEVEL).build()
.doGetAsync(info, new OkHttpUtil.CallbackOk() {
@Override
public void onResponse(HttpInfo info) throws IOException {
if(info.isSuccessful()){
InfoBean bean = info.getRetDetail(InfoBean.class);
// You can operate the UI directly.
}
}
});
}

HttpInfo构建扩展了一个新方法build(this),将当前页面设置为一个tag标记进行请求的绑定。在OkHttpUtil工具类中增加以下两个方法:

/**
* 保存请求集合
* @param info
* @param call
*/
private void putCall(HttpInfo info, Call call){
if(null != info.getTag()){
List<Call> callList = callsMap.get(info.getTag());
if(null == callList){
callList = new LinkedList<Call>();
callList.add(call);
callsMap.put(info.getTag(),callList);
}else{
callList.add(call);
}
}
}

/**
* 取消请求
* @param clazz
*/
public static void cancelCall(Class<?> clazz){
List<Call> callList = callsMap.get(clazz);
if(null != callList){
for(Call call : callList){
if(!call.isCanceled())
call.cancel();
}
callsMap.remove(clazz);
}
}


这样就完成了请求的绑定、保存与取消等操作,但问题来了,取消请求的方法在什么时候调用呢?答案当然是Activity/Fragment销毁时调用。下面需要编写一个Activity生命周期的回调接口,并注册到App的Application中,首先在Application中注册,代码如下

private OkHttpUtil.BaseActivityLifecycleCallbacks activityLifecycleCallbacks;

@Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(activityLifecycleCallbacks = new OkHttpUtil.BaseActivityLifecycleCallbacks());
}


在OkHttpUtil中添加以下代码:

/**
* Activity声明周期回调
*/
public static class BaseActivityLifecycleCallbacks implements Application.ActivityLifecycleCallbacks {

@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {

}

@Override
public void onActivityStarted(Activity activity) {

}

@Override
public void onActivityResumed(Activity activity) {

}

@Override
public void onActivityPaused(Activity activity) {

}

@Override
public void onActivityStopped(Activity activity) {

}

@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {

}

@Override
public void onActivityDestroyed(Activity activity) {
cancelCall(activity.getClass());
}
}

大家应该注意到 cancelCall(activity.getClass());方法的调用。整个逻辑贯通起来,每次请求调用putCall方法,在销毁时调用cancelCall方法,这样就完成了请求与Activity/Fragment生命周期绑定的功能了。

任务2,异步请求采用UI线程回调方式将在下面一篇文章中来叙述下。

最后贴一下HttpInfo的代码(增加了请求标识tag):

package okHttp;

import android.app.Activity;
import android.support.v4.app.Fragment;
import android.text.TextUtils;
import com.google.gson.Gson;
import java.util.HashMap;
import java.util.Map;

public class HttpInfo {

//**请求参数定义**/
private String url;//请求地址
private Map<String,String> params;//请求参数

//**响应返回参数定义**/
private int retCode;//返回码
private String retDetail;//返回结果

protected Class<?> tag;

public HttpInfo(Builder builder) {
this.url = builder.url;
this.params = builder.params;
this.tag = builder.tag;
}

public static Builder Builder() {
return new Builder();
}

public static final class Builder {

private String url;
private Map<String,String> params;
private Class<?> tag;

public Builder() {
}

public HttpInfo build(){
return new HttpInfo(this);
}

public HttpInfo build(Object object){
setTag(object);
return new HttpInfo(this);
}

public Builder setUrl(String url) {
this.url = url;
return this;
}

public Builder addParams(Map<String, String> params) {
this.params = params;
return this;
}

public Builder addParam(String key,String value){
if(null == this.params)
this.params = new HashMap<String,String>();
if(!TextUtils.isEmpty(key))
this.params.put(key,value);
return this;
}

public Builder setTag(Object object) {
if(object instanceof Activity){
Activity activity = (Activity) object;
this.tag = activity.getClass();
}
if(object instanceof Fragment){
Fragment fragment = (Fragment) object;
this.tag = fragment.getActivity().getClass();
}
return this;
}

}

//**请求返回常量定义**/
public final int NonNetwork = 1;
private final String NonNetwork_Detail = "网络中断";
public final int SUCCESS = 2;
private final String SUCCESS_Detail = "发送请求成功";
public final int ProtocolException = 3;
private final String ProtocolException_Detail = "请检查协议类型是否正确";
public final int NoResult = 4;
private final String NoResult_Detail = "无法获取返回信息(服务器内部错误)";
public final int CheckURL = 5;
private final String CheckURL_Detail = "请检查请求地址是否正确";
public final int CheckNet = 6;
private final String CheckNet_Detail = "请检查网络连接是否正常";
public final int ConnectionTimeOut = 7;
private final String ConnectionTimeOut_Detail = "连接超时";
public final int WriteAndReadTimeOut = 8;
private final String WriteAndReadTimeOut_Detail = "读写超时";

public HttpInfo packInfo(int retCode){
return packInfo(retCode, null);
}

public HttpInfo packInfo(int retCode, String retDetail){
this.retCode = retCode;
switch (retCode){
case NonNetwork:
this.retDetail = NonNetwork_Detail;
break;
case SUCCESS:
this.retDetail = SUCCESS_Detail;
break;
case ProtocolException:
this.retDetail = ProtocolException_Detail;
break;
case NoResult:
this.retDetail = NoResult_Detail;
break;
case CheckURL:
this.retDetail = CheckURL_Detail;
break;
case CheckNet:
this.retDetail = CheckNet_Detail;
break;
case ConnectionTimeOut:
this.retDetail = ConnectionTimeOut_Detail;
break;
case WriteAndReadTimeOut:
this.retDetail = WriteAndReadTimeOut_Detail;
break;
}
if(!TextUtils.isEmpty(retDetail)){
this.retDetail = retDetail;
}
return this;
}

public boolean isSuccessful(){
if(this.retCode == SUCCESS)
return true;
return false;
}

public String getUrl() {
return url;
}

public String getRetDetail() {
return retDetail;
}

public <T> T getRetDetail(Class<T> clazz){
return new Gson().fromJson(retDetail, clazz);
}

public void setRetDetail(String retDetail) {
this.retDetail = retDetail;
}

public Map<String, String> getParams() {
return params;
}

public Class<?> getTag() {
return tag;
}
}


项目已上传至GitHub:https://github.com/MrZhousf/OkHttp3
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: