Android modularization - network module encapsulation

In practical application development, the commonly used network frameworks are OkHttp, Retrofit, RxJava+RxAndroid, each of which has its own advantages: for example, OkHttp, because of its unique interceptor responsibility chain mode, can intercept requests and responses; Retrofit internally encapsulates OkHttp, which is more efficient in using annotations to encapsulate Http requests, which was also used in Retrofit before; RxJava's advantages Potential lies in its operator, the transformation of events.

Each framework has its own advantages, so through the integration of all the request framework, to achieve multi domain, multi environment, clear structure of the network module, so it is imperative to encapsulate the network request module in the project.

1. Basic theory

First, we introduce the message format of request and response in Http.

(1) get request message format

------Part I: request line
It mainly includes request method GET, URL (Interface), protocol version (Http1.0 or Http1.1)

------Part II: request header
Host: domain name (www.xxxxx.xxx), Connection (if Http1.1, it will default to Keep Alive), acceptance related fields (such as Accept language, Accept encoding)

(2) get request response message

------Part I: response line

Status code, status code description, protocol version

------Part II: response header

Server: server description, Connection: long Connection, response type content type: json data......

------Part III: response body

Load response data

The difference between Post request and get request is that in the request message format, the requested data is placed in the request body.

2. Build network module

(1) Retrofit network request module

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) {

           }
        });

Generally, using Retrofit in application is such a process. Create a method in the Model and request the method to make network request internally.

(2) Add log interceptor

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

Log interceptor is mainly used to print the process of request and response when network requests, and return each field value in the message.

 public static OkHttpClient getOkHttpClient(){
        OkHttpClient.Builder okhttpclient = new OkHttpClient.Builder();
        if(iNetWorkRequiredInfo != null && iNetWorkRequiredInfo.isDebug()){
            //http intercept, print message
            HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
            loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
            okhttpclient.addInterceptor(loggingInterceptor);
        }
        //Add interceptor
        okhttpclient.addInterceptor(new CommonRequestInterceptor(iNetWorkRequiredInfo));
        return okhttpclient.build();
    }

(3) Add interceptors for requests and responses

In the actual development process, it is usually necessary to add fields in the request header or intercept some fields in the response, and it is also necessary to use OkHttp's interceptor implementation.

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 {
        //Create request
        Request.Builder builder = chain.request().newBuilder();
        //Add request header
        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 {
        //Execute request return response
        Response response = chain.proceed(chain.request());
        if(!response.header("Set-Cookie").isEmpty()){
            //There are many cookie fields, only the JSessionId field is needed
            for (String header :
                    response.headers("Set-Cookie")) {
                if (header.contains("JSESSIONID")) {
                    //Save cookies locally

                }
            }
        }
        return response;
    }
}

(4) RxJava support

The advantages of RxJava don't need to be discussed here. Look at the code.

        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 onError(Throwable e) {

            }

            @Override
            public void onComplete() {

            }
        });
    }

(5) Optimize architecture

After the observer subscribes, there are four methods behind, which are not beautiful. Therefore, you can extract an abstract Observer class, and then only need to make a successful or failed callback.

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 onError(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) Business interface

In the network layer, it mainly encapsulates network request, OkHttp interceptor, log interceptor and other operations. The specific business must be completed in the app, so the api interface and javabean class in the network layer must be put into the business module.

For the Retrofit object, it needs to be used in the app.

//Save the Retrofit object
    private static HashMap<String,Retrofit> retrofitMap = new HashMap<>();

Instead of using a single design pattern, you can use HashMap to store Retrofit pairs. key is the name of BaseUrl + service. When calling the same api, if you have created Retrofit objects before, you can take them directly from the collection.

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();
        //If not, add Retrofit to the map collection
        retrofitMap.put(Constant.BASE_URL + service.getName(),retrofit);
        return retrofit;
    }
//Unified interface call
     public static <T> T getService(Class<T> service){
        return getRetrofit(service).create(service);
     }

(7) Encapsulation of thread scheduling

When the business layer calls the api, it needs to do thread switching.

 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) {

                            }
                        });

This part can be extracted and switched with compose. In the compose method, it is the incoming ObservableTransformer. Therefore, in the network module, create a thread scheduling class.

//Encapsulation of thread switching
    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;
            }
        };
    }

Using compose in the business module is very simple.

 NetWorkApi.getService(INetworkApi.class).getDataByRxJava(0)
                        //Encapsulation of thread switching
                        .compose(NetWorkApi.applyScheduler(new BaseObserver<ArticleBean>() {
                            @Override
                            protected void onSuccess(ArticleBean articleBean) {

                            }
                            @Override
                            protected void onFailed(Throwable e) {

                            }
                        }));
44 original articles published, 10 praised, 5002 visited
Private letter follow

Tags: Retrofit network OkHttp JSON

Posted on Sat, 07 Mar 2020 23:29:01 -0500 by netman182