1. Introduction

Rrtrofit is very scalable, and if you are not familiar with Retrofit, it is difficult to cope with a wide variety of requirements. So, here’s a simple encapsulation. Mainly for the following three requirements:

2. How can I use it easily

To keep things simple, I did the following.

Here, I won’t go into details about how Retrofit singleton works, but the code is as follows:

Retrofit.Builder builder = new Retrofit.Builder() .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .addConverterFactory(SecurityGsonConverterFactory.create()) .baseUrl("xxx") client = new OkHttpClient().newBuilder() .addNetworkInterceptor(new HttpLoggingInterceptor() .setLevel(HttpLoggingInterceptor.Level.BODY)) .addNetworkInterceptor(new StethoInterceptor()) .addInterceptor(new SecurityInterceptor(context)) .retryOnConnectionFailure(true) // TODO: ConnectTimeout (5_000, timeunit.milliseconds). ReadTimeout (5_000, TimeUnit.MILLISECONDS) .build() retrofit = builder.client(client).build()Copy the code

The SecurityInterceptor and SecurityGsonConverterFactory, said in a later.

Let’s take a look at how code is written with the introduction of RxJava. Take obtaining user information as an example.

Api

    @FormUrlEncoded
    @POST("v1/api.user.profile.get")
    Observable get(
            @Field("uid") String uid
    );Copy the code

First, we need the ServiceApi object, which is briefly wrapped as follows:

    public static  T createApi(Class clz) {
        return (T) retrofit.create(clz);
    }Copy the code

Where we need it, usually in the Model, in the constructor, we initialize it.

this.userApi = RetrofitClient.createApi(UserApi.class)Copy the code

Next up is ->Observable

Observable observable = userApi.get(params[0]);Copy the code

And then Subscriber, because I’ve encapsulated Subscriber as well, but let’s leave it at that. Let’s take a look at the code

NormalSubscriber subscriber = new NormalSubscriber(context) { @Override public void onNext(UserResponse userResponse) { response.onSuccess(userResponse, UserModel.class, ApiHelper.userApi.GET); }};Copy the code

As an additional note, HttpResponse is an interface that is encapsulated.

public interface HttpResponse {
    void onSuccess(T response, Class clz,String methodName);
    void onError(Throwable t);
}
Copy the code

Finally, the subscription operation is performed

CoreUtil.subscribe(observable, subscriber)Copy the code

The corresponding detailed code is:

    public static  void subscribe(Observable observable, Subscriber subscriber) {
        observable
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(subscriber)
    }Copy the code

This dependency makes the process very simple.

  1. Start by creating serviceApi in the model constructor,
  2. Making network requests

The network request code, after a little encapsulation into the following pseudocode.

Observable observable = friendApi.applylist(); NormalSubscriber subscriber = new NormalSubscriber(context) { @Override public void onNext(FriendApplyListResponse friendListResponse) { response.onSuccess(friendListResponse,FriendModel.class,ApiHelper.friendApi.APPLYLIST); }}; CoreUtil.subscribe(observable,subscriber);Copy the code

Because I’m still doing traditional MVC, so in onSuccess, I need the following: Response, Model.class, interface name. This makes it easier to distinguish between activities.

3. How to encrypt and decrypt data

Said here, the SecurityGsonConverterFactory mentioned above, SecurityInterceptor prayed for. First, encryption:

3.1 the encryption

In the SecurityInterceptor intercept method, the code is as follows:

Request request = chain.request(); RequestBody oldBody = request.body(); Buffer buffer = new Buffer(); oldBody.writeTo(buffer); StringBuffer stringBuffer = new StringBuffer(); String s; while ((s = buffer.readUtf8Line()) ! = null) { stringBuffer.append(s); } StringBuilder newString = encrypt(stringBuffer.toString().trim());Copy the code

The encrypt method is used to encrypt parameters. You can write it according to your company’s requirements.

Then. Just reorganize it

        RequestBody body = RequestBody.create(mediaType, newString)
        request = request.newBuilder()
                .header("Content-Type", body.contentType().toString())
                .header("Content-Length", String.valueOf(body.contentLength()))
                .header("Authorization", SESSION.getInstance().getToken())
                .header("UserAgent", "Platform/Android, Device/" + model + ", Lang/" + UserAgent.getInstance().lang + ", ScreenWidth/" + UserAgent.getInstance().width + ", ScreenHeight/" + UserAgent.getInstance().height)
                .header("UDID", UserAgent.getInstance().UDID)
                .header("Ver", UserAgent.getInstance().ver)
                .header("Sign", signString)
                .method(request.method(), body)
                .build()
        Response response = chain.proceed(request)Copy the code

This is the general process, so we have completed the parameter encryption process.

3.1 the decryption

This involves SecurityGsonConverterFactory, is the difference between this and GsonConverterFactory SecurityGsonResponseBodyCoverter, convert methods in this class, decryption.

String encryptString = value.string(); JSONObject jsonObject = null; try { jsonObject = new JSONObject(encryptString.trim()); String decrypt_data = XXTEA.decryptBase64StringToString(jsonObject.optString("data"), UserAppConst.AppDataKey); JsonObject = new jsonObject (decrypt_data); } catch (JSONException e) { e.printStackTrace(); } JsonReader jsonReader = gson.newJsonReader(new StringReader(jsonObject.toString())); try { return adapter.read(jsonReader); }finally { value.close(); }Copy the code

Of course, the corresponding server above should return data like this:

{success: XXX error_code: XXX data:{XXX}}Copy the code

Here’s a bit of advice. Of course, error data can also be put in data, such as what Token is invalid and so on. However, HTTP code 400 is required to be returned at this time. Why? So it’s easy for us to do error handling.

4. Error handling

Our error handling is in NormalSubscriber mentioned above. Let’s see. We’re doing this in onError, and just to be clear, in onError, there are two cases where onError is called

  • abnormal
  • Isn’t the server 200-299 corresponding? (PS: guess, if you know, let me know. Because of the small business, I haven’t met it before.)
public void onError(Throwable e) {
        
        if (e instanceof ConnectException) {
            ToastUtil.toastShow(mContext, e.getLocalizedMessage());
            return;
        }
        
                       String errorJson = ((HttpException) e).response().errorBody().string();
                JSONObject jsonObject = new JSONObject(errorJson);
                String errorMessage = jsonObject.optString("data");

}Copy the code

5. To summarize

The above approach has solved most of the problems in our company’s current projects. I believe you should also be useful, know about it.