Implementation of Android http request by Rxjava2+Retrofit2

[Exchange only, reprinting is strictly prohibited] Github Demo address click here:

Preface

This article won't talk about Retrofit2 (my last article) On Retrofit2 It's not about Rxjava2 alone. The theme is: Rxjava2+Retrofit2 implements Android http requests.

Http Api Return Results Processing

At present, the structure of the api returned from our project is roughly as follows:

This structure is very common. Only Result is different in the whole structure. It's OK to use generics to deal with it.

/**
 * This class is related to the specific business API structure. The API structure of this Demo is roughly as follows:
 * 
 * Created by anylife.zlb@gmail.com on 2016/7/11.
 */
public class HttpResponse<T> {
    private int code;
    private String error;
    private T result;
        // some set and some get
    public T getResult() {
        return result;
    }

    public void setResult(T result) {
        this.result = result;
    }
}

So how do you define an api?

Return to Observable < HttpResponse < T >, generic T is related to specific Api, focusing on the following combination with Rxjava2

public interface ApiService {
    /**
     * pick up information
     *
     */
    @GET("api/lebang/staffs/me/detail")
    Observable&lt;HttpResponse&lt;StaffMsg&gt;&gt; getStaffMsg();

    /**
     * Login ,Ordinary ways to log in and use Rxjava can be
     */
    @POST("api/lebang/oauth/access_token1")
    Call&lt;HttpResponse&lt;LoginResult&gt;&gt; goLoginByRetrofit(@Body LoginParams loginParams);

So how do you write http requests in Rxjava2?

We know that the simplest stream processing in Rxjava is as follows: Observable.subscribe(Observer);
Take getting employee information as an example.

ApiService.getStaffMsg()
                  .subscribeOn(Schedulers.io())
                  .observeOn(AndroidSchedulers.mainThread());  //These two lines of code need to be saved
                  .subscribe(new Observer&lt;HttpResponse&lt;LoginResult&gt;&gt;() {
                    @Override
                    public void onSubscribe(Disposable d) {      
                    }
                    @Override
                    public void onNext(HttpResponse&lt;LoginResult&gt; loginResultHttpResponse) {

                    }
                    @Override
                    public void onError(Throwable e) {

                    }

It doesn't matter if you want to write like this, but obviously there's a lot of redundant code:

  • The data returned by HttpResponse < T > we just want to care about T. The other parts of HttpResponse are the same.
  • There is no need for each interface to handle onError, and most of the Http error exception handling can extract commonalities
  • Subscribed threads are the same as observed threads and are duplicated code.
  • What if a rogress Dialog prompt for a network request is needed?

In summary, we need to re-encapsulate Observer

public abstract class BaseObserver&lt;T&gt; implements Observer&lt;HttpResponse&lt;T&gt;&gt; {
    private final String TAG = BaseObserver.class.getSimpleName();
    private final int RESPONSE_CODE_OK = 0;       //Customized business logic to successfully return positive data
    private final int RESPONSE_CODE_FAILED = -1;  //Failure to return data, serious error
    private Context mContext;
    private static Gson gson = new Gson();
    private int errorCode;
    private String errorMsg = "Unknown error!";

    /**
     * Rewrite the onSuccess method according to the specific Api business logic! Error is chosen to rewrite, but must Super!
     * @param t
     */
    public abstract void onSuccess(T t);

    /**
     * @param mContext
     * @param showProgress By default, the process needs to be displayed. If not, please pass false.
     */
    public  BaseObserver(Context mContext, boolean showProgress) {
        this.mContext = mContext;
        if (showProgress) {
            HttpUiTips.showDialog(mContext, true, null);
        }
    }
    @Override
    public final void onSubscribe(Disposable d) {
        //dddddddddddddd
    }

    @Override
    public final void onNext(HttpResponse&lt;T&gt; response) {
        HttpUiTips.dismissDialog(mContext);
        if (response.getCode() == RESPONSE_CODE_OK) {
            onSuccess(response.getResult());
        } else {
            onFailure(response.getCode(), response.getError());
        }
    }

    @Override
    public final void onError(Throwable t) {
        HttpUiTips.dismissDialog(mContext);
        if (t instanceof HttpException) {
            HttpException httpException = (HttpException) t;
            errorCode = httpException.code();
            errorMsg = httpException.getMessage();
            getErrorMsg(httpException);
        } else if SocketTimeoutException) {  //VPN open
            errorCode = RESPONSE_CODE_FAILED;
            errorMsg = "Server response timeout";
        } 

        // .....(t instanceof  XXXXXXXXX
        onFailure(errorCode, errorMsg);
    }

    /**
     * Simply get rid of Dialog
     */
    @Override
    public final void onComplete() {
    }

    /**
     * Default error dispose!
     * Usually it's Alert Dialog or SnackBar.
     *
     * @param code
     * @param message
     */
    @CallSuper  //if overwrite,you should let it run.
    public void onFailure(int code, String message) {
        if (code == RESPONSE_CODE_FAILED &amp;&amp; mContext != null) {
            HttpUiTips.alertTip(mContext, message, code);
        } else {
            disposeEorCode(message, code);
        }
    }

    /**
     * Unified Interception Processing for General Problem
     * @param code
     */
    private final void disposeEorCode(String message, int code) {
        switch (code) {
            case 101:
            case 401:
                //Back to the login page
                Intent intent = new Intent();
                intent.setClass(mContext, LoginActivity.class);
                mContext.startActivity(intent);
                break;
        }
        Toast.makeText(mContext, message + "   code=" + code, Toast.LENGTH_SHORT).show();
    }

    /**
     * Get detailed error information errorCode,errorMsg, which is related to the Api structure, and here is related to the Api structure!
     * For example, when Grant_type is deliberately miswritten at login time, http should return 401=httpException.code() directly.
     * But how did it lead to 401? Our server will be explained in content in respose.errorBody
     */
    private final void getErrorMsg(HttpException httpException) {
        String errorBodyStr = "";
        try {   //UniCode transcoding is not necessary for our project!
            errorBodyStr = TextUtils.convertUnicode(httpException.response().errorBody().string());
        } catch (IOException ioe) {
            Log.e("errorBodyStr ioe:", ioe.toString());
        }
        try {
            HttpResponse errorResponse = gson.fromJson(errorBodyStr, HttpResponse.class);
            if (null != errorResponse) {
                errorCode = errorResponse.getCode();
                errorMsg = errorResponse.getError();
            } else {
                errorCode = RESPONSE_CODE_FAILED;
                errorMsg = "ErrorResponse is null";
            }
        } catch (Exception jsonException) {
            errorCode = RESPONSE_CODE_FAILED;
            errorMsg = "http Request error Json Information anomaly";
            jsonException.printStackTrace();
        }
    }

}

In this way, our call can be very simple after encapsulation. Many of the onFailure interfaces can be handled directly without Override. The data returned by onSuccess will do. Where. compose(RxObservableUtils.applySchedulers()) handles threads

               .subscribeOn(Schedulers.io())
               .observeOn(AndroidSchedulers.mainThread());   

It becomes a line of code. The call in Activity is as follows. It's simpler without Override.

        HttpCall.getApiService().getStaffMsg()
                .compose(RxObservableUtils.applySchedulers())
                .subscribe(new BaseObserver&lt;StaffMsg&gt;(this,true) {
                    @Override
                    public void onSuccess(StaffMsg staffMsg) {

                    }

                    @Override
                    public void onFailure(int code, String message) {
                        super.onFailure(code, message);
                    }
                });

Attention should be paid to the combination of Rxjava and Retrofit

  • Prevent memory leaks, combined with RxLifeCycler
  • %&%#$&####^(#

See more https://github.com/AnyLifeZLB/AndroidAppFrameWork

Keywords: github Android network VPN

Added by muitine on Sat, 06 Jul 2019 20:53:58 +0300