基于OkGo(OkHttp)的统一请求响应小封装
2018-09-11 本文已影响1090人
阿敏其人
OkGo基于OkHttp。
我们根据OkGo做一点小封装。
OkHttp的Converter很好用,但是,String更加灵活,我们这里不用Converter。
特点
- 请求统一入口
方便统一处理,比如请求头添加参数之类的 - 响应统一处理,也可指定单独处理
默认统一处理,返回格式比较特殊的可单独处理 - request和response打印
看请求参数,看响应内容,结合Ohkttp的拦截器 - 省缺模式选择复写回调接口
每次都只复写onSuccess和onFinish,需要onError和onStart之类,再选择性复写
小封装开始
OkGo配置
1、应用级gradle
implementation 'com.lzy.net:okgo:3.0.4'
2、Applicaiton初始化
public class MyApplication extends Application{
@Override
public void onCreate() {
super.onCreate();
initOkGo();
}
private void initOkGo() {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor("OkGo");
//log打印级别,决定了log显示的详细程度
loggingInterceptor.setPrintLevel(HttpLoggingInterceptor.Level.BODY);
//log颜色级别,决定了log在控制台显示的颜色
loggingInterceptor.setColorLevel(Level.INFO);
builder.addInterceptor(loggingInterceptor);
//全局的读取超时时间 基于前面的通道建立完成后,客户端终于可以向服务端发送数据了
builder.readTimeout(OkGo.DEFAULT_MILLISECONDS, TimeUnit.MILLISECONDS);
//全局的写入超时时间 服务器发回消息,可是客户端出问题接受不到了
builder.writeTimeout(OkGo.DEFAULT_MILLISECONDS, TimeUnit.MILLISECONDS);
//全局的连接超时时间 http建立通道的时间
builder.connectTimeout(OkGo.DEFAULT_MILLISECONDS, TimeUnit.MILLISECONDS);
//使用sp保持cookie,如果cookie不过期,则一直有效
builder.cookieJar(new CookieJarImpl(new SPCookieStore(this)));
//使用数据库保持cookie,如果cookie不过期,则一直有效
//builder.cookieJar(new CookieJarImpl(new DBCookieStore(this)));
//使用内存保持cookie,app退出后,cookie消失
//builder.cookieJar(new CookieJarImpl(new MemoryCookieStore()));
// === 配置https ===
//方法一:信任所有证书,不安全有风险
/*HttpsUtils.SSLParams sslParams1 = HttpsUtils.getSslSocketFactory();
//方法二:自定义信任规则,校验服务端证书
HttpsUtils.SSLParams sslParams2 = HttpsUtils.getSslSocketFactory(new SafeTrustManager());
//方法三:使用预埋证书,校验服务端证书(自签名证书)
HttpsUtils.SSLParams sslParams3 = HttpsUtils.getSslSocketFactory(getAssets().open("srca.cer"));
//方法四:使用bks证书和密码管理客户端证书(双向认证),使用预埋证书,校验服务端证书(自签名证书)
HttpsUtils.SSLParams sslParams4 = HttpsUtils.getSslSocketFactory(getAssets().open("xxx.bks"), "123456", getAssets().open("yyy.cer"));
builder.sslSocketFactory(sslParams1.sSLSocketFactory, sslParams1.trustManager);
//配置https的域名匹配规则,详细看demo的初始化介绍,不需要就不要加入,使用不当会导致https握手失败
builder.hostnameVerifier(new SafeHostnameVerifier());*/
// === 请求头 和 参数的 设置 ===
//---------这里给出的是示例代码,告诉你可以这么传,实际使用的时候,根据需要传,不需要就不传-------------//
/*HttpHeaders headers = new HttpHeaders();
headers.put("commonHeaderKey1", "commonHeaderValue1"); //header不支持中文,不允许有特殊字符
headers.put("commonHeaderKey2", "commonHeaderValue2");
HttpParams params = new HttpParams();
params.put("commonParamsKey1", "commonParamsValue1"); //param支持中文,直接传,不要自己编码
params.put("commonParamsKey2", "这里支持中文参数");*/
OkGo.getInstance().init(this) //必须调用初始化
.setOkHttpClient(builder.build()) //建议设置OkHttpClient,不设置将使用默认的
.setCacheMode(CacheMode.NO_CACHE) //全局统一缓存模式,默认不使用缓存,可以不传
.setCacheTime(CacheEntity.CACHE_NEVER_EXPIRE) //全局统一缓存时间,默认永不过期,可以不传
.setRetryCount(3); //全局统一超时重连次数,默认为三次,那么最差的情况会请求4次(一次原始请求,三次重连请求),不需要可以设置为0
//.addCommonHeaders(headers) //全局公共头
//.addCommonParams(params);
}
}
AndroidManifest指定一下Application。
网络权限配置一下。
封装工具类
主工具类
/**
* User: AMQR
* Date&Time: 2018-09-11 & 10:36
* Describe: 这个类存在的意义是为了做请求的统一处理
* 不要conver转对象,原生数据处理起来才可以灵活变通
*/
public class OkGoUtils {
/**
* 网络请求的相关参数
*/
public static class RequestOption{
public Context context;
public Map params;
public String url;
public AbsPostJsonStringCb iPostJsonStringCb;
/**
* 是否同意处理response相应码
* 一般来说都是默认统一处理,当后端部分接口返回不规范的时候,需要单独处理,
*/
public boolean isNormalDeal = true;
public JSONObject mJSONObject;
//public LoadHelpView loadHelpView;
}
/**
* post请求
* 以String形式返回数据,以post方式提交,包装这一层,是为了统一处理数据
*/
public static void postJsonStringCallback(final RequestOption requestOption){
JSONObject jsonObject;
if(requestOption.mJSONObject!=null){
jsonObject = requestOption.mJSONObject;
}else{
jsonObject = new JSONObject(requestOption.params);
}
OkGo.<String>post(requestOption.url)
//.tag()
.upJson(jsonObject)
.headers("Authorization", "本地存储Token")
.execute(new StringCallback() {
@Override
public void onSuccess(Response<String> response) {
String resp = response.body().toString();
FortuneLogUtils.d(requestOption.url+" ======= >>>>>> 请求详情: "+"\n"+"request:"+requestOption.url+"\n"+"params: "+requestOption.params+"\n"+"response: "+resp);
// 是否需要 统一的处理
if(requestOption.isNormalDeal){
if(unifiedProcessingCode(resp, requestOption)){
backToSuccessNormal(resp, requestOption);
}
}else{
backToSuccessOriginal(resp, requestOption);
}
}
@Override
public void onError(Response<String> response) {
super.onError(response);
FtToastUtil.showShort(requestOption.context,"请求失败,请稍后在试");
FortuneLogUtils.d("网络请求异常:"+response.toString());
if(response.body()!=null){
String err = response.body().toString();
FortuneLogUtils.e("======= request faile:"+requestOption.url+"\n"+"params: "+requestOption.params+"\n"+"response: "+err);
}
if(requestOption.iPostJsonStringCb !=null){
requestOption.iPostJsonStringCb.onError(response);
}
}
@Override
public void onStart(Request<String, ? extends Request> request) {
super.onStart(request);
if(requestOption.iPostJsonStringCb !=null){
requestOption.iPostJsonStringCb.onStart(request);
}
}
@Override
public void onFinish() {
super.onFinish();
if(requestOption.iPostJsonStringCb !=null){
requestOption.iPostJsonStringCb.onFinish();
}
}
});
}
/**
* 返回码的统一处理
* 当返回 true 时,代表success。
* @param resp
* @param requestOption
* @return
*/
private static boolean unifiedProcessingCode(String resp, final RequestOption requestOption) {
if(!TextUtils.isEmpty(resp)){
try {
JSONObject jsonObject = new JSONObject(resp);
String code= jsonObject.optString("code");
// 假设返回码200为通过
if(code.equals("200")){
return true;
}else if (code.equals("1001")) { // 其他错误码处理
FtToastUtil.showShort(requestOption.context, "验证码错误");
}
} catch (JSONException e) {
e.printStackTrace();
}
}
return false;
}
/**
* 某些错误码的出现,应该让程序直接抛到登录页面
* @param requestOption
* @param content
*/
private static void gotoLogin(final RequestOption requestOption, String content) {
// code...
}
/**
* get请求
* @param requestOption
*/
public static void getJsonStringCallback(final RequestOption requestOption){
if(requestOption.params!=null && requestOption.params.size()>0){
Map<String,String> map = requestOption.params;
boolean isFirst = true;
StringBuffer stringBuffer= new StringBuffer();
for (Map.Entry<String, String> entry : map.entrySet()) {
if(isFirst){
stringBuffer.append("?"+entry.getKey()+"="+entry.getValue());
isFirst = false;
}else{
stringBuffer.append("&"+entry.getKey()+"="+entry.getValue());
}
}
requestOption.url = requestOption.url+stringBuffer.toString();
}
OkGo.<String>get(requestOption.url)
// header 参数,如果需要的话
.headers("Authorization", "本地存储")
//.tag()
.execute(new StringCallback() {
@Override
public void onSuccess(Response<String> response) {
String resp = response.body().toString();
FortuneLogUtils.d("======= request:"+"\n"+requestOption.url+"\n"+"response: "+resp);
// 是否需要 统一的处理
if(requestOption.isNormalDeal){
if(unifiedProcessingCode(resp,requestOption)){
backToSuccessNormal(resp, requestOption);
}
}else{
backToSuccessOriginal(resp, requestOption);
}
}
@Override
public void onError(Response<String> response) {
super.onError(response);
FtToastUtil.showShort(requestOption.context,"请求失败,请稍后在试");
if(response.body()!=null){
FortuneLogUtils.d("网络请求异常:"+response.toString());
String err = response.body().toString();
FortuneLogUtils.e("======= request faile:"+requestOption.url+"\n"+"response: "+err);
}
if(requestOption.iPostJsonStringCb !=null){
requestOption.iPostJsonStringCb.onError(response);
}
}
@Override
public void onStart(Request<String, ? extends Request> request) {
super.onStart(request);
if(requestOption.iPostJsonStringCb !=null){
requestOption.iPostJsonStringCb.onStart(request);
}
}
@Override
public void onFinish() {
super.onFinish();
if(requestOption.iPostJsonStringCb !=null){
requestOption.iPostJsonStringCb.onFinish();
}
}
});
}
/**
* 请求success 通用处理
* @param resp
* @param requestOption
*/
private static void backToSuccessNormal(String resp, RequestOption requestOption) {
if(requestOption.iPostJsonStringCb !=null){
try {
JSONObject jsonObject = new JSONObject(resp);
String data = jsonObject.getString("data");
requestOption.iPostJsonStringCb.onSuccess(resp,data);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 请求成功,原生字符串处理
* @param resp
* @param requestOption
*/
private static void backToSuccessOriginal(String resp, RequestOption requestOption) {
if(requestOption.iPostJsonStringCb !=null){
requestOption.iPostJsonStringCb.onSuccess(resp,resp);
}
}
}
.
.
省缺接口
public interface IPostJsonStringCb {
void onSuccess(String str,String data);
void onError(Response<String> response);
void onStart(Request<String, ? extends Request> str);
void onFinish();
}
.
.
抽象类
public abstract class AbsPostJsonStringCb implements IPostJsonStringCb{
// 抽象类里面复写的方法后面作为 非必选方法。
@Override
public void onError(Response<String> response) {
}
@Override
public void onStart(Request<String, ? extends Request> str) {
}
}
使用示例
findViewById(R.id.mTv).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String url = ApiUrl.baseAdd + ApiUrl.login;
OkGoUtils.RequestOption requestOption = new OkGoUtils.RequestOption();
Map<String,String> map = new HashMap();
map.put("memberName", "zhangsan");
map.put("memberPass", "123456");
requestOption.context = MainActivity.this;
requestOption.url = url;
requestOption.params = map;
/**
* 如果不需要采用响应统一处理,requestOption.isNormalDeal = false;
* 如果想统一处理,则requestOption.isNormalDeal = true; 或者不传,默认就是true
*/
requestOption.isNormalDeal = false;
requestOption.iPostJsonStringCb = new AbsPostJsonStringCb() {
@Override
public void onSuccess(String str, String data) {
FortuneLogUtils.d("success:"+str);
FortuneLogUtils.d("success:"+data);
}
@Override
public void onError(Response<String> response) {
super.onError(response);
FortuneLogUtils.d("onError:"+response.getException());
}
@Override
public void onFinish() {
FortuneLogUtils.d("onFinish:");
}
};
OkGoUtils.postJsonStringCallback(requestOption);
}
});
代码都附上了,除了几个Log、Toast和Api类没附上而已。
东西本来也不复杂,放上来,只是为了临时写个demo方便,所以成文。
本文至此完,谢谢阅读。