Android模块化-----网络模块封装

在实际的应用开发中,常用到的网络框架有OkHttp、Retrofit、RxJava+RxAndroid,每个框架都有自己的优点:例如OkHttp,因为其特有的拦截器责任链模式,可以拦截请求和响应;Retrofit内部封装OkHttp,它更高效在于使用注解封装Http请求,在之前Retrofit中也使用过;RxJava的优势在于它的操作符,事件的转换。

每个框架都有自己的优点,因此通过整合全部的请求框架,来实现多域名、多环境、结构清晰的网络模块,因此在项目封装网络请求模块势在必行。

1、基础理论

首先先介绍一下Http中请求和响应的报文格式。

(1)get请求报文格式
Android模块化-----网络模块封装
------第一部分:请求行
主要包括请求方法GET、URL(接口)、协议版本(Http1.0或者Http1.1)

------第二部分:请求头
Host:域名(www.xxxxx.xxx)、Connection(如果是Http1.1会默认是长连接 Keep Alive)、与Accept相关的字段(像Accept-Language、Accept-Encoding)…

(2)get请求响应报文
Android模块化-----网络模块封装
------第一部分:响应行

状态码、状态码描述、协议版本

------第二部分:响应头

Server:服务器端的描述、Connection:长连接、响应的类型Content-type:json数据。。。。。。

------第三部分:响应体

装载响应数据

Post请求方式与get请求不同的是:请求报文格式中,请求的数据放在请求体中。

2、搭建网络模块

(1)Retrofit网络请求模块

implementation 'com.squareup.retrofit2:retrofit:2.7.1'
implementation 'com.squareup.okhttp:okhttp:2.7.5'
implementation 'com.squareup.retrofit2:converter-gson:2.7.1'
Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(Constant.BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
                INetworkApi iNetworkApi = retrofit.create(INetworkApi.class);
        Call<ArticleBean> call = iNetworkApi.getData(0);
        call.enqueue(new Callback<ArticleBean>() {
            @Override
           public void onResponse(Call<ArticleBean> call, Response<ArticleBean> response) {
                Log.e("TAG","response==="+response.body().toString());
            }

            @Override
            public void onFailure(Call<ArticleBean> call, Throwable t) {

           }
        });

一般在应用中使用Retrofit就是这样的流程,在Model创建一个方法,请求这个方法在内部进行网络请求。

(2)添加日志拦截器

implementation 'com.squareup.okhttp3:logging-interceptor:4.4.0'

日志拦截器,主要是打印在网络请求时,请求和响应的过程,返回报文中的各个字段值。

 public static OkHttpClient getOkHttpClient(){
        OkHttpClient.Builder okhttpclient = new OkHttpClient.Builder();
        if(iNetWorkRequiredInfo != null && iNetWorkRequiredInfo.isDebug()){
            //http拦截,打印报文
            HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
            loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
            okhttpclient.addInterceptor(loggingInterceptor);
        }
        //添加拦截器
        okhttpclient.addInterceptor(new CommonRequestInterceptor(iNetWorkRequiredInfo));
        return okhttpclient.build();
    }

(3)添加请求和响应的拦截器

在实际开发过程中,通常需要在请求的头部添加字段或者截取响应中的某些字段,同样也需要使用OkHttp的拦截器实现。

public class CommonRequestInterceptor implements Interceptor {
    private final INetWorkRequiredInfo netWorkRequiredInfo;

    public CommonRequestInterceptor(INetWorkRequiredInfo netWorkRequiredInfo){
        this.netWorkRequiredInfo = netWorkRequiredInfo;
    }
    @NotNull
    @Override
    public Response intercept(@NotNull Chain chain) throws IOException {
        //创建请求
        Request.Builder builder = chain.request().newBuilder();
        //添加请求头
        builder.addHeader("Content-Type","application/json;charset=UTF-8");
        return chain.proceed(builder.build());
    }
}
public class CommonResponseInterceptor implements Interceptor {
    private final INetWorkRequiredInfo requiredInfo;

    public CommonResponseInterceptor(INetWorkRequiredInfo requiredInfo){
        this.requiredInfo = requiredInfo;
    }
    @NotNull
    @Override
    public Response intercept(@NotNull Chain chain) throws IOException {
        //执行请求返回响应
        Response response = chain.proceed(chain.request());
        if(!response.header("Set-Cookie").isEmpty()){
            //cookie字段有很多,只需要有JSessionId的字段
            for (String header :
                    response.headers("Set-Cookie")) {
                if (header.contains("JSESSIONID")) {
                    //将Cookie保存在本地

                }
            }
        }
        return response;
    }
}

(4)支持RxJava

RxJava的优点就不必在此多说,看代码吧。

        Observable<ArticleBean> observable = iNetworkApi.getDataByRxJava(0);
        observable.subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<ArticleBean>() {
            @Override
            public void onSubscribe(Disposable d) {

            }

            @Override
            public void onNext(ArticleBean articleBeanLiveData) {

            }

            @Override
            public void one rror(Throwable e) {

            }

            @Override
            public void onComplete() {

            }
        });
    }

(5)优化架构

在观察者订阅之后,有4个方法拖在后面,不太美观,因此可以抽取一个抽象的Observer类,然后只需要做请求成功或者失败的回调。

public abstract class BaseObserver<T> implements Observer<T> {
    @Override
    public void onSubscribe(Disposable d) {

    }
    @Override
    public void onNext(T t) {
        onSuccess(t);
    }
    @Override
    public void one rror(Throwable e) {
        onFailed(e);
    }
    @Override
    public void onComplete() {

    }
    protected abstract void onSuccess(T t);
    protected abstract void onFailed(Throwable e);
}
.subscribe(new BaseObserver<ArticleBean>() {
            @Override
            protected void onSuccess(ArticleBean articleBeanLiveData) {
                Log.e("TAG","livedata==="+articleBeanLiveData);
            }

            @Override
            protected void onFailed(Throwable e) {

            }
        });

(6)业务接口

在网络层中,主要封装网络请求、OkHttp拦截器、日志拦截等操作,具体的业务还是得在app中完成,所以之前在网络层中的api接口以及javabean类都必须放到业务模块。

那么对于Retrofit对象,就需要拿到app当中使用。

//保存Retrofit对象
    private static HashMap<String,Retrofit> retrofitMap = new HashMap<>();

不用单例设计模式,使用HashMap存储Retrofit对也可以,key就是BaseUrl + service的名字,在调用同一个api的时候,如果之前已经创建了Retrofit对象,那么就直接从集合中拿。

public static Retrofit getRetrofit(Class service) {
        if(retrofitMap.get(Constant.BASE_URL + service.getName()) != null){
            return retrofitMap.get(Constant.BASE_URL + service.getName());
        }

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(Constant.BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .client(getOkHttpClient())
                .build();
        //如果不存在,就将Retrofit添加到map集合
        retrofitMap.put(Constant.BASE_URL + service.getName(),retrofit);
        return retrofit;
    }
//统一的接口调用
     public static <T> T getService(Class<T> service){
        return getRetrofit(service).create(service);
     }

(7)线程调度的封装

在业务层调用api时,需要做线程切换。

 NetWorkApi.getService(INetworkApi.class).getDataByRxJava(0)
                        .subscribeOn(Schedulers.io())
                        .observeOn(AndroidSchedulers.mainThread())
                        .subscribe(new BaseObserver<ArticleBean>() {
                            @Override
                            protected void onSuccess(ArticleBean articleBean) {
                                
                            }

                            @Override
                            protected void onFailed(Throwable e) {

                            }
                        });

这一部分是可以抽出来,使用compose来切换的,在compose方法中,是传入的ObservableTransformer,因此在网络模块中,创建一个线程调度的类。

//线程切换的封装
    public static <T> ObservableTransformer<T,T> applyScheduler(final Observer<T> observer){
        return new ObservableTransformer<T, T>() {
            @Override
            public ObservableSource<T> apply(Observable<T> upstream) {
                Observable<T> observable = upstream.subscribeOn(Schedulers.io())
                        .observeOn(AndroidSchedulers.mainThread());
                observable.subscribe(observer);
                return observable;
            }
        };
    }

在业务模块中使用compose就非常的简洁。

 NetWorkApi.getService(INetworkApi.class).getDataByRxJava(0)
                        //做线程切换的封装
                        .compose(NetWorkApi.applyScheduler(new BaseObserver<ArticleBean>() {
                            @Override
                            protected void onSuccess(ArticleBean articleBean) {

                            }
                            @Override
                            protected void onFailed(Throwable e) {

                            }
                        }));
上一篇:Mac OS X Server上的Java:游戏结束了吗?


下一篇:android-阻止请求拦截器进行翻新?