This frame comes from the existing project, these days opened a new project just use this frame out of the hand, but also convenient to use in the future. There are so many Rxjava2+Retrofit2 packages on the web, but the general idea is the same, and many of the code is similar, this is no exception, you can choose to use it. First of all, we don’t talk about encapsulation ideas, first talk about this framework has what functions and how to use;

function

1 Use the RxCache mechanism to customize the cache expiration time and data paging cache. Unified request error handling; 3 unified network state judgment processing; 4 Print request logs based on httploggingtor.

This framework does not encapsulate progressBars as other frameworks do. Because progressbars have different style requirements for each project, even the same project may have different pull-down refresh and normal loading. So you need to define the ProgressBar yourself. Furthermore, the framework uses RxCache instead of OKHttp for caching, so there are no requirements on the server to define headers or anything like that. If you’re not familiar with RxCache, check out this article or the RxCache website. Don’t know why so cattle frame start is only 1000, don’t talk nonsense, look at the way of use.

use

Call the following code to complete the network request

// declare a listener
HttpSubscriber mHttpObserver =new HttpSubscriber(new OnResultCallBack<TestBean>() {
        @Override
        public void onSuccess(TestBean tb) {
        }
        @Override
        public void onError(int code,String errorMsg) {
        }
    });
// Initiate a request
HttpManager.getInstance().getDatas(mHttpObserver,1.10."json".true);

// Cancel the request
 mHttpObserver.unSubscribe();Copy the code

Doesn’t it look easy?

Here’s how the above code completes the network data request. Let’s take a look at the structure of this framework

There are only seven classes.

ApiResponse — encapsulates the returned data template (error_code, reason and result names need to be matched with the background partner. Error_code is usually the code status code, and reason indicates the success or failure message. ApiService — Retrofit’s data request interface. Notice the return value type of each method. (What we really need is data in the TestBean that must be wrapped by the ApiResponse and returned as an Observable.) CacheProvider — RxCache’s cache interface, Note that its first parameter type must be the same as the return value type of the Retrofit data request interface. OnResultCallBack – Request a successful or failed callback. ApiException — Common request error handling class. HttpSubscriber — common request subscriber. HttpManager – The management class that initiates the request.

The first is the various library files introduced

//Rxjava2
compile 'the IO. Reactivex. Rxjava2: rxjava: 2.0.7'
compile 'the IO. Reactivex. Rxjava2: rxandroid: 2.0.1'
//Retrofit2
compile 'com.squareup.retrofit2:retrofit:latest.release'
compile 'com.squareup.retrofit2:converter-gson:latest.release'
compile 'com. Jakewharton. Retrofit: retrofit2 - rxjava2 - adapter: 1.0.0'
//RxCache
compile "Com. Making. VictorAlbertos. RxCache: runtime: 1.8.0 comes with - 2 x"
compile 'com. Making. VictorAlbertos. Jolyglot: gson: 0.0.3'
//Okhttp-interceptor
compile 'com. Squareup. Okhttp3: logging - interceptor: 3.6.0'Copy the code

Initialization of HttpManager

public static HttpManager getInstance() {
    if (instance == null) {
        synchronized (HttpManager.class) {
            if (instance == null) {
                instance = newHttpManager(); }}}return instance;
}Copy the code

Singleton HttpManager, look at the constructor of HttpManager

private HttpManager() {
    HttpLoggingInterceptor.Level level= HttpLoggingInterceptor.Level.BODY;
    HttpLoggingInterceptor loggingInterceptor=new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
        @Override
        public void log(String message) {
            Log.i("HttpManager",message); }}); loggingInterceptor.setLevel(level); OkHttpClient.Builder builder =new OkHttpClient.Builder();
    builder.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
            .retryOnConnectionFailure(true)
            .addInterceptor(loggingInterceptor);
    OkHttpClient okHttpClient = builder.build();

    mRetrofit = new Retrofit.Builder()
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .baseUrl(Constant.BASE_URL)
            .client(okHttpClient)
            .build();

    cacheProvider = new RxCache.Builder()
            .persistence(mContext.getFilesDir(), new GsonSpeaker())
            .using(CacheProvider.class);

    mApiService = mRetrofit.create(ApiService.class);
}Copy the code

In the constructor, we first set up the interceptor with Httploggingtor and set it to okHttpClient.Builder with the addInterceptor method. This is followed by building okHttpClient. Builder and OkHttpClient, followed by the initialization of Retrofit. This is followed by the initialization of RxCache, where the cache directory is set. MContext is ApplicationContext, passed in by the init method.

public class App extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        HttpManager.init(this);// Do nothing but cache the Application reference}}Copy the code

So how does HttpManager complete a network request?

1 Declare the request interface in ApiService

@FormUrlEncoded
@POST("query? key=7c2d1da3b8634a2b9fe8848c3a9edcba")
Observable<ApiResponse<TestBean>> getDatas(@Field("pno") int pno, @Field("ps") int ps, @Field("dtype") String dtype);Copy the code

Declare the cache interface in 2CacheProvider (write if you need to cache)

@LifeCache(duration = 5, timeUnit = TimeUnit.MINUTES)
Observable<ApiResponse<TestBean>> getDatas(Observable<ApiResponse<TestBean>> oRepos, EvictProvider evictDynamicKey);Copy the code

Note the annotations for customizing the cache expiration time. (The EvictProvider parameter sets whether to cache the requested data. See here.) The first parameter must be Observable> the return value of getDatas declared in ApiService. 3 HttpManager declares that the corresponding request method has two methods, with caching

  public void getDatasWithCache(Observer<TestBean> subscriber, int pno, int ps, String dtype, boolean update) {
    toSubscribe(cacheProvider.getDatas(mApiService.getDatas(pno, ps,dtype),new EvictProvider(update)), subscriber);
}Copy the code

No caching

public void getDatasNoCache(Observer<TestBean> subscriber, int pno, int ps, String dtype) {
    toSubscribe(mApiService.getDatas(pno, ps,dtype), subscriber);
}Copy the code

See no cache-free methods except that they are not wrapped in cacheProvider.getDatas () and are missing an update parameter that controls whether or not to update. Now look at the implementation of the toSubscribe () method

private <T> void toSubscribe(Observable<ApiResponse<T>> o, Observer<T> s) {
    o.subscribeOn(Schedulers.io())
            .map(new Function<ApiResponse<T>, T>() {
                @Override
                public T apply(@NonNull ApiResponse<T> response) throws Exception {
                    int code=Integer.parseInt(response.getCode());
                    if(code! =Constant.SUCCESS_CODE) {throw new ApiException(code, response.getMsg());
                    } else {
                        return response.getDatas();
                    }
                }
            })
            .unsubscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(s);
}Copy the code

Use Rxjava’s Map method to convert the data further, and notice that SUCCESS_CODE is the status code for the data returned successfully. If the code! The getApiExceptionMessage method in ApiException, where you can define different messages based on your code. Or use the incoming message. Normally this class does not need to be modified. If the client needs to customize the message according to the code, it can be modified as above. In the end all messages are thrown to HttpSubscriber’s onError method

    @Override
public void onError(Throwable e) {
    if (e instanceof CompositeException) {
        CompositeException compositeE=(CompositeException)e;
        for (Throwable throwable : compositeE.getExceptions()) {
            if (throwable instanceof SocketTimeoutException) {
                mOnResultListener.onError(ApiException.Code_TimeOut,ApiException.SOCKET_TIMEOUT_EXCEPTION);
            } else if (throwable instanceof ConnectException) {
                mOnResultListener.onError(ApiException.Code_UnConnected,ApiException.CONNECT_EXCEPTION);
            } else if (throwable instanceof UnknownHostException) {
                mOnResultListener.onError(ApiException.Code_UnConnected,ApiException.CONNECT_EXCEPTION);
            } else if (throwable instanceof RxCacheException) {
                // Cache exception is not handled temporarily
            }  else if (throwable instanceofMalformedJsonException) { mOnResultListener.onError(ApiException.Code_MalformedJson,ApiException.MALFORMED_JSON_EXCEPTION); }}}else {
        String msg = e.getMessage();
        int code;
        if (msg.contains("#")) {
            code = Integer.parseInt(msg.split("#") [0]);
            mOnResultListener.onError(code, msg.split("#") [1]);
        } else{ code = ApiException.Code_Default; mOnResultListener.onError(code, msg); }}}Copy the code

Network issues are also addressed uniformly in this approach. Note that different network states return different status codes.

SocketTimeoutException Network timeout 1000 ConnectException Connection exception 1001 UnknownHostException Host exception 1001 MalformedJsonException Parsing exception 1020 Other error messages return error code from the server, where the “#” is concatenated in the getApiExceptionMessage() method in ApiException. Final execution to

mHttpObserver =new HttpSubscriber(new OnResultCallBack<TestBean>() {
        @Override
        public void onSuccess(TestBean tb) {
        }
        @Override
        public void onError(int code,String errorMsg) {
        }
    });Copy the code

, where we can display different interfaces according to different codes (such as common network error interfaces), or give users hints through Toast or other methods. Back to the toSubscribe method, if the data returns successfully, code==SUCCESS_CODE, then the data is returned to the onNext method of HttpSubscriber

@Override
public void onNext(T t) {
    if(mOnResultListener ! =null) { mOnResultListener.onSuccess(t); }}Copy the code

OnNext calls OnResultCallBack’s onSuccess method, passing the data to

mHttpObserver =new HttpSubscriber(new OnResultCallBack<TestBean>() {
        @Override
        public void onSuccess(TestBean tb) {
        }
        @Override
        public void onError(int code,String errorMsg) {
        }
    });Copy the code

In onSuccess, where we just show the data to the user. Another task of HttpSubscriber is to cancel the data request operation. The current Disposable is recorded by a global mDisposable in onSubscribe

 @Override
public void onSubscribe(Disposable d) {
    mDisposable = d;
}Copy the code

Just call unSubscribe() where you want to cancel

public void unSubscribe() {
    if(mDisposable ! =null&&! mDisposable.isDisposed()) { mDisposable.dispose(); }}Copy the code

Let’s run the program

   mHttpObserver =new HttpSubscriber(new OnResultCallBack<TestBean>() {
        @Override
        public void onSuccess(TestBean tb) {
            for (TestBean.ListBean bean : tb.getList()) {
                result+=bean.toString();
            }
            resultTv.setText(result);
        }
        @Override
        public void onError(int code,String errorMsg) {
            resultTv.setText("onError: code:"+code+" errorMsg:"+errorMsg ); }});Copy the code

In this case, TextView displays the data on success and error message and code on failure. The first is not using caching

 HttpManager.getInstance().getDatasNoCache(mHttpObserver,1.10."json");Copy the code






Set up a 5-minute cache

@LifeCache(duration = 5, timeUnit = TimeUnit.MINUTES)
Observable<ApiResponse<TestBean>> getDatas(Observable<ApiResponse<TestBean>> oRepos, EvictProvider evictDynamicKey);

 HttpManager.getInstance().getDatasWithCache(mHttpObserver,1.10."json".false);Copy the code

The first request generates network traffic, indicating that the data is from the network. The subsequent requests do not generate traffic, indicating that the data is from the local cache. Well this framework is introduced here, there is a need to download here github.com/shiweibsw/E…

How to use it?

Build. Gradle. Copy the HTTP package to your project.

Next step plan

The Retrofit interface class encapsulates basic GET and POST requests; 2 Support importing projects in the form of plug-ins.

Gold digging technology essay juejin.cn/post/684490…