Android网络开源库-Retrofit(五)简易封装

来源:互联网 发布:php 16进制 编辑:程序博客网 时间:2024/06/17 17:33

1.前言

Rrtrofit的扩展性很强,如果对retrofit不熟悉的话,是很难应对各种各样的需求的。因此,在这里,做一下简单的封装。主要为了下面三点需求:

  1. 使用简单
  2. 加密处理
  3. 错误处理

2.怎样才能简单使用

为了简单粗暴,我做了以下工作。

  • 使用单例Retrofit
  • 引入RxJava

在这里,如何Retrofit单例化,就不多说了,大致代码如下:

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: 2016/8/24 缓存、cookie等        .connectTimeout(5_000, TimeUnit.MILLISECONDS)        .readTimeout(5_000, TimeUnit.MILLISECONDS)        .build();retrofit = builder.client(client).build();

其中的SecurityInterceptor和SecurityGsonConverterFactory,在稍后会说。

我们来看下引入RxJava之后代码如何编写。以一个获取用户信息为例。

Api

    @FormUrlEncoded    @POST("v1/api.user.profile.get")    Observable<UserResponse> get(            @Field("uid") String uid    );

首先,我们需要ServiceApi对象,在这里进行一次简单封装,如下:

    public static <T> T createApi(Class<T> clz) {        return (T) retrofit.create(clz);    }

在需要的地方,一般是model里,在构造函数中,我们初始化。

this.userApi = RetrofitClient.createApi(UserApi.class);

接下来就是->Observable

Observable<UserResponse> observable = userApi.get(params[0]);

接着便是,Subscriber,因为这里我对Subscriber也进行了封装,但是我们这里先暂时不管。先看下代码

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

,需要额外说明的是,HttpResponse,是封装的一个接口。

public interface HttpResponse {    <T>void onSuccess(T response, Class<?> clz,String methodName);    void onError(Throwable t);}

,最后,进行订阅操作

CoreUtil.subscribe(observable, subscriber);

这个对应的详细代码为:

    public static <T> void subscribe(Observable<T> observable, Subscriber<T> subscriber) {        observable                .subscribeOn(Schedulers.io())                .unsubscribeOn(Schedulers.io())                .observeOn(AndroidSchedulers.mainThread())                .subscribe(subscriber);    }

这么依赖,过程就非常简单了。

  1. 首先在model的构造函数中create serviceApi,
  2. 进行网络请求

而网络请求的代码,经过稍微的封装就变为以下伪代码。

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

因为,我这里还是传统mvc,因此,在onSuccess里,需要以下内容,Response,Model.class,接口名称。这样,在Activity里才好区分。

3.如何进行加密解密

说道这里,上面提到过的SecurityGsonConverterFactory,SecurityInterceptor就祈祷作用了。先说加密:

3.1 加密

在SecurityInterceptor的intercept方法当中,相关代码如下:

        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());

上诉encrypt 方法就是进行参数加密的,各位可以根据自己公司的需求进行编写。

然后。进行重组即可

        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);

大致过程就是这样,这样,我们就完成了参数加密的过程。

3.1 解密

这涉及到了SecurityGsonConverterFactory,这个和GsonConverterFactory的区别之处就在于SecurityGsonResponseBodyCoverter,在这个类的convert方法中,进行解密。

        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();        }

当然,上面对应的服务器返回数据应该是这样的:

//伪数据啊  json格式的{    success:xxx    error_code:xxx    data:{        xxx    }}

在这里,我有一点建议。就是我们前面对应的UserResponse应该是data里的数据,当然,data里也可以放error数据,比如说什么Token失效了等等,但是,这个时候要求返回http code 400,为什么呢?这样方便我们做错误处理。

4.错误处理

我们这里的错误处理就在上面提到过得NormalSubscriber里。我们来看看。我们在onError里做处理,需要说明的是,onError里,有两种情况会调用onError

  • 出现异常
  • 服务器不是200-299相应吗(ps:猜测,知道的朋友告诉下,因为业务小的关系,没遇到过)
public void onError(Throwable e) {        // TODO: 2016/9/2 添加其他异常判断        if (e instanceof ConnectException) {            ToastUtil.toastShow(mContext, e.getLocalizedMessage());            return;        }        //当然这里还有其他异常,比如说SocketTimeoutException,MalformedJsonException,IllegalStateException等等。这些异常是代码引起的异常,我们需要了解另一种异常。HttpException,这个异常很重要,这是我们错误处理的关键,比如说我们token过期了,在服务器返回的数据里面,data里应该是tiken无效,并且 http code应该是400,bad request。                       String errorJson = ((HttpException) e).response().errorBody().string();                JSONObject jsonObject = new JSONObject(errorJson);                String errorMessage = jsonObject.optString("data");//这里的errorMessage应该就是错误原因了。我们可以根据这个或者,error_code进行对应的处理}

5.总结

上面的这种方法,解决了我们公司 目前项目的绝大部分问题。相信对你们应该也是有用的,了解一下吧。

7 0
原创粉丝点击