基于OkGo(OkHttp)的统一请求响应小封装

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方便,所以成文。

本文至此完,谢谢阅读。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,761评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,953评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,998评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,248评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,130评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,145评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,550评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,236评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,510评论 1 291
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,601评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,376评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,247评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,613评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,911评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,191评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,532评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,739评论 2 335

推荐阅读更多精彩内容