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.
- Start by creating serviceApi in the model constructor,
- 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.