Android简单基类封装(三)OKhttp网络请求——其实你也可以

本文介绍如何抛弃那些高大上的、花里胡哨的、适配所有的完美http封装(壳子而已)。

学习地址:https://github.com/weimingjue/http

首先,OKhttp是现在所有安卓开发的网络请求框架(还在用Apache的我就不多说什么了,自行绕道),那些所谓的完美封装只是在OKhttp上加了几行代码而已。

其次,那些封装也是要考虑全局性,只是把OKhttp简化了一两行而已,真正用的时候并没有方便太多。如下,网络请求获取text并展示需要做的操作

由于多数博客鱼龙混杂,本博客如果让你非常满意或解决了大家的根本性问题,希望多多支持在下方点赞和回复一下,举手之劳方便大家。

final Dialog loading=new LaodingDialog(this);//添加进度条
Body body=new Body();
body.put("token","xxx");
body.put("activityId",1);
XXHttp.getInstance()//单例(自己还单独封装了一层,设置了请求时间等)
        .addHeader(new Header().add("userId",1).add("type","json")...)//添加header
        .url("http...").tag("http...").post()//添加url并设置post
        .body(body.build())//添加body
        .build().execute(new XXListener(){//回调
            @Override
            public void onError(int errorCode) {//网络失败相关
                loading.dismiss();//关闭对话框
                switch (errorCode){
                    case 1:
                        //提示1
                        break;
                ...
                    default:
                        break;
                }
            }
            @Override
            public void onSuccess(final Response response) {//网络畅通
                runOnUiThread(new Runnable() {//需要回到主线程,有的甚至还用了handler
                    @Override
                    public void run() {
                        loading.dismiss();
                        if (response.code()==200){//需要判断请求状态
                            XXBean bean = JSON.parseObject(body, XXBean.Class);//解析后台数据
                            if (bean.code==200){//后台状态码
                                if (!XXActivity.this.isFinish()){//还得判断Activity是否挂了
                                    mTv.setText(bean.data.text);//终于完成了
                                }
                            }else {
                                //提示2
                            }
                        }else {
                            //提示3
                        }
                    }
                });
            }
        });

虽然写的可能有些极端,但上述问题或多或少都有遇到,下面我就给大家展示一下封装后的效果吧

HttpUtils.postDialog(this, "http...",
        MapUtils.getHttpInstance().put("activityId", 1),
        XXBean.class, new OKHttpListener() {
            @Override
            public void onSuccess(XXBean bean) {
                mTv.setText(bean.data.text);
            }
        });

由一个40多行冗长的代码变成了8行简短的代码,上面所做的这里都有,这到底经历了什么?请看下回分析...?

 

 

 

不!!!现在就要告诉你其实这很简单。

我们先分析一下出现这种情况的原因:

所谓条条大路通罗马,你要想请求到网络数据可谓是有千万种方式,对于我们普通人来讲虽然方式多,但世界上这么多路根本无从选择。

Android简单基类封装(三)OKhttp网络请求——其实你也可以_第1张图片

 所以OKhttp诞生了,OKhttp将路修好并规范化

Android简单基类封装(三)OKhttp网络请求——其实你也可以_第2张图片

虽然路是修好了,但路依然很多,经常会出现走反、绕路或到死胡同的情况。

所以一些第三方框架也诞生了,将路添加了导航功能,这样就一定能到达罗马

Android简单基类封装(三)OKhttp网络请求——其实你也可以_第3张图片

虽然第三方框架最终能到达,但每次到路口都需要查看路牌,看路牌就要浪费时间。

其实我们的目的其实很简单,就是快速的到达罗马。根据开车经验,我们只需要熟悉几条路即可(防止堵车),如下才是我们真正需要的

Android简单基类封装(三)OKhttp网络请求——其实你也可以_第4张图片

 不扯这么远了,进入正题吧

还是老样子,先理思路:

1.封装基类问题:别人的封装是基于OKhttp的,但自己用的比较繁琐,所以直接封装OKhttp;

2.header问题:每次都要加上userId和json,所以应该将header封装进去;

3.body问题:我们的body应该是链式的,这样方便put,还有token当然也要封装进去;

4.dialog问题:我的项目默认是showdialog的,所以也需要封装进去,但不是每个接口都要dialog,所以可以为null;

5.线程问题:线程切换太麻烦,当然必须在封装层解决,另外Thread当然不如AsyncTask了(有人说AsyncTask100多个线程就不行了,请问你的app同时开了100多线程还能用吗,系统的东西不是随随便便就玩坏的);

6.网络问题:每次都要判断网络的正确性,当然必须封装了;

7.解析问题:每次都要fastjson解析一下不烦吗,封装起来岂不更好;

8.服务器返回不同状态码问题:这个我也懒得管,当然封装;

9.Activity finish问题:没有对Activity finish判断,经常崩溃,但判断又很烦躁,你说呢;

第一步:当然是导包了(博主很懒,懒得升级了)

    implementation 'com.squareup.okhttp3:okhttp:3.6.0'
    implementation 'com.squareup.okio:okio:1.6.0'

第二步:OKhttpClient是ok的核心,每次都build一个其实没啥意义,写成单例的更好还省内存

    private static final OkHttpClient mClient = new OkHttpClient.Builder()
            .connectTimeout(15, TimeUnit.SECONDS)
            .writeTimeout(20, TimeUnit.SECONDS)
            .readTimeout(20, TimeUnit.SECONDS)
            .build();

 第三步:搭框子,这就是关键的问题了,我们该如何搭建工具类?

有人说,既然链式编程这么火,当然是如下这样了

HttpUtils.getInstance().setActivity(this).url("http...").setJsonClass(XXBean.Class)
.body(new Body().put("activityId",1)).post().clinet(new ...);

但有没有想过链式编程也是要一步一步的,这和别人封装的不就一样了吗,你的路口只是比别人少了几个而已。我说过,我们是要直通罗马的,显然链式编程并不适合我们。

初步思想当然是先写一个支持post、get、dialog、解析、finish、body、服务器判断的方法了

    /**
     * 
     * @param activity 可以对finish进行判断
     * @param httpUrl
     * @param body
     * @param type post还是get
     * @param dialog
     * @param mClass 有class才能解析
     * @param   要想对服务器的状态判断当然必须有个BaseBean了
     * @param listener  回调监听
     */
    public static  void http(Activity activity, String httpUrl, Map body,@type int type, Dialog dialog,Class mClass,OKHttpListener listener){
        
    }

但是这参数也太太太多了吧。。。其实作为工具类就一个方法合适吗。所以我们应该重载派生一些出来。

将其拆分成post和get,当你写Request.Builder就会发现post和get都是它,另外get的body并没太大卵用,还有重载并不能明显区分post和get,所以就成了这样

    //类型 utf-8
    public static final MediaType mMediaType = MediaType.parse("application/json;charset=UTF-8");

    public static  void httpGet(Activity activity, String httpUrl, Dialog dialog, Class mClass, OKHttpListener listener) {
        http(activity, httpUrl, new Request.Builder(), dialog, mClass, listener);
    }

    public static  void httpPost(Activity activity, String httpUrl, Map body, Dialog dialog, Class mClass, OKHttpListener listener) {
        if (body.get("token") == null) {//已经有了当然最好不要替换了
            body.put("token", 用户token);
        }
        http(activity, httpUrl, new Request.Builder().post(RequestBody.create(mMediaType, JSON.toJSONString(body))), dialog, mClass, listener);
    }

    public static  void http(Activity activity, String httpUrl, Request.Builder builder, Dialog dialog, Class mClass, OKHttpListener listener) {

    }

再将httpGet、httpPost拆分成httpGetDialog、httpGetDefault、httpPostDialog、httpPostDefault,此时已经无法再分了,也许你感觉这样分有什么用,等你用的时候就知道了,只要不超过10个还是非常方便的。

等你封装完成之后使用时就会发现:1.有些数据在Activity finish时可能还需要用到;2.类似HashMap不是链式编程,使用不方便;3.特殊情况的网络请求无法解决。

解决方案:1.为了可拓展性,写一个接口HttpInterface由Activity的基类继承即可,这样的话基类fragment、基类adapter等继承之后都可以愉快的传this了

public interface HttpInterface {
    Activity getActivity();

    //是否丢弃http请求的数据数据
    boolean isDiscardHttp();
}

2.写一个Map直接继承JSONObject(看准了是fastjson的),将put重写即可,并且toString就可以变成json字符串

@MainThread
public final class MapUtils extends JSONObject implements Serializable {
    private static MapUtils mMap = new MapUtils();

    private MapUtils() {
    }

    /**
     * 返回自己
     */
    @Override
    public MapUtils put(@NonNull String k, Object v) {
        if (v instanceof CharSequence) {//CharSequence说明是字符串
            v = v.toString();
        }
        super.put(k, v);
        return this;
    }

    @Nullable
    public Object get(@NonNull String k) {
        return super.get(k);
    }

    ///////////////////////////////////////////////////////////////////////////
    // 以下是获取方法
    ///////////////////////////////////////////////////////////////////////////

    //获得一个新的实例
    public static MapUtils getNewInstance() {
        return new MapUtils();
    }

    /**
     * 只能使用在网络请求,其他地方请使用{@link JSONObject}或{@link #getNewInstance}
     * 获得单一实例,注意代码执行顺序,当是list的时候使用{@link #getNewInstance}或直接使用{@link com.alibaba.fastjson.JSONArray}
     */
    public static MapUtils getHttpInstance() {
        mMap.clear();
        return mMap;
    }
}

3.将最初的http再次抽象剥离(可能参数更多,主要是为了备用)

public static  void httpCustom(final HttpInterface httpInterface, final String httpUrl,
                                                       Request.Builder builder, final DialogPopwindowInterface dialog,
                                                       final Class mClass, final OkHttpClient client, final OKHttpListener listener) {

由于代码太多,学习地址见:https://github.com/weimingjue/http

你可能感兴趣的:(Android封装基类,android教程,不做框架只做UI)