Android simple package RxJava + Retrofit

Nowadays, the combined use of RxJava and Retrofit is estimated to be quite common, and it has been used in my own work all the time. In the process of using it, we will package it and use it. There are also many packaged projects on GitHub that can be used directly. In fact, the secondary packaging of open source frameworks is sometimes more or less in the process of packaging different business logic. Some are different, it is recommended to package and use it by yourself. This will not only improve your understanding of the original framework, but also improve your packaging capabilities. It is easier to start if you need to make changes during the work process. Well, without further ado, here is a simple sample for your reference.


add dependencies

compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'io.reactivex.rxjava2:rxjava:2.x.y'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.2'
implementation 'com.squareup.okhttp3:logging-interceptor:3.10.0'
compile 'com.squareup.retrofit2:converter-gson:2.3.0'
compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'

I don't want to say more about adding dependencies. I think everyone knows, but when I first came into contact with this knowledge, I wonder if anyone will find and add some dependencies when reading online articles? For example: com.squareup.retrofit2:converter-gson:2.3.0we want to add a GsonConverterdependency. Will it be confusing for those who are new to this knowledge and who don't often visit GitHub? Regardless of whether it will or not, anyway, I was really confused when I first came into contact with it. Here is a reminder for those who have been confused, we can view the corresponding dependencies by opening the subfile of the project on GitHub. For example, in the Retrofit project on GitHub: retrofit/retrofit-converters/gson/you can view the corresponding GsonConverterdependencies under this path.

Encapsulate Retrofit (singleton mode)

public class HttpRequest {
    
    

    public static final long CONNECTTIME = 30000;

    public static final String BASE_URL = "http://jxhdapi.ooowin.com/";

    private  ApiService apiService;

    public HttpRequest() {
        //添加日志拦截器
        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
            @Override
            public void log(String message) {
                Log.d("TAG", "==========" + message);
            }
        }).setLevel(HttpLoggingInterceptor.Level.BODY);

        //获取OkHttpClient
        OkHttpClient client = new OkHttpClient.Builder()
                .connectTimeout(CONNECTTIME, TimeUnit.MICROSECONDS)
                .readTimeout(CONNECTTIME,TimeUnit.MICROSECONDS)
                .writeTimeout(CONNECTTIME,TimeUnit.MICROSECONDS)
                .addInterceptor(interceptor)
                .addNetworkInterceptor(new HttpHeaderInterceptor())
                .build();

        //初始化Retrofit
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .client(client)
                .build();

        apiService = retrofit.create(ApiService.class);
    }

    //  创建单例
    private static class SingletonHolder {
    
    
        private static final HttpRequest INSTANCE = new HttpRequest();
    }

    public static ApiService getApi(){
        return SingletonHolder.INSTANCE.apiService;
    }

}

Here we can see that two interceptors have been added: the log interceptor and the network request Header interceptor. We all know that for Retrofit, we can directly convert it GsonConverterinto an entity class, but sometimes we want to get its json To view the data, we can implement it by adding a log interceptor at this time, but we must set setLevelthe method for it, and the data printed out by setting different attributes is different. As for adding a header interceptor, I think everyone should know that the headers required by the interface in normal work are the same, so we need to add them uniformly:

public class HttpHeaderInterceptor implements Interceptor {
    
    
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        Request build = request.newBuilder()
//                .addHeader("","")   添加header
                .build();
        return chain.proceed(build);
    }
}

encapsulation entity class

{
    "code": 1,
    "msg": "操作成功",
    "data": {······}
}

Usually the json data we get from the server is like the above, and some returned field content formats are fixed, such as: code and msg. Some are uncertain, such as: data. At this time, we need to perform secondary processing on it. We can write a base class:

public class BaseBean<T> {
    private int code;
    private String msg;
    private T data;

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}

Use generics to represent data in an uncertain format in data. Here, a data interface for obtaining all provinces in the country is used for testing:

public interface ApiService {

    //获取省列表
    @GET("common/areas")
    Flowable<BaseBean<List<Province>>> province();

}

After the entity class is encapsulated, we can test it:

HttpRequest.getApi()
            .province()
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Subscriber<BaseBean<List<Province>>>() {
                @Override
                public void onSubscribe(Subscription s) {

                }

                @Override
                public void onNext(BaseBean<List<Province>> listBaseBean) {

                }

                @Override
                public void onError(Throwable t) {

                }

                @Override
                public void onComplete() {

                }
            });
}

Through the above code, it is not difficult to see that this is the effect of encapsulation, but we will find that we have to add a scheduler and rewrite Subscriberseveral methods every time for such a request? Wouldn't that still be cumbersome. Yes, then we will encapsulate these.

Use the compose operator

public class SchedulersHelper implements FlowableTransformer{
    
    

    @Override
    public Publisher apply(Flowable upstream) {
        return  upstream.subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread());
    }
}

Using the compose operator can directly operate on the current Flowable, so we can naturally add the operation of switching threads here. The next step is Subscriber for encapsulation.

Package Subscriber

public abstract class MySubscriber<T> implements Subscriber<T>{
    @Override
    public void onSubscribe(Subscription s) {
        s.request(Long.MAX_VALUE);
        showLoading();
    }

    @Override
    public void onNext(T t) {
        //code为1代表服务器返回成功的数据
        if (((BaseBean)t).getCode() == 1) {
            //成功后返回data数据进行处理即可
            onSuccess((T) ((BaseBean) t).getData());
        }else {
            //处理服务器返回错误code
        }
    }

    @Override
    public void onComplete() {
        finishLoading();
    }

    @Override
    public void onError(Throwable t) {
        finishLoading();
        //处理网络异常
        Log.d("TAG","=========" + t);
    }

    protected abstract void onSuccess(T t);

    protected abstract void showLoading();

    protected abstract void finishLoading();
}

As shown above, we judge whether it is successful according to the code returned by the server, and then send the data data. The error codes returned by the server and network request errors can all be processed here in a unified manner. Then we go to test the interface.

test

HttpRequest.getApi().province()
        .compose(new SchedulersHelper())
        .subscribe(new MySubscriber() {
            @Override
            protected void onSuccess(Object o) {

            }

            @Override
            protected void showLoading() {

            }

            @Override
            protected void finishLoading() {

            }
        });

It can be seen that the operation process has become very simple. We don’t need to put showLoading()these finishLoading()two methods here. This is written in it for the convenience of testing.

Finish

At this point, the encapsulation of RxJava + Retrofit is over. This is a very simple encapsulation process without using too much complicated logic. It is relatively easy to understand, and the completeness of the package may not be very high. You can use it as a reference and use your own understanding to better package it. I wrote a simple MVP base class before, and I put it in the previous project for this encapsulation process. It constitutes a simple, easy-to-understand and easy-to-use: a small demo of RxJava + Retrofit + MVP, which is placed on GitHub. You can check RxRetrofitMvp . If you think it is helpful to you, please give it a star, hahaha!

Guess you like

Origin blog.csdn.net/zl_china/article/details/79467558