Retrofit+RxJava的使用

Retrofit+RxAndroid的使用

这一段时间,除了流行的React Native之外,还有不少流行的框架如RetrofitRx等等。

Retrofit简介:

在Android API4.4之后,Google官方使用了square公司推出的okHttp替换了HttpClient的请求方式。后来square公司又推出了基于okHttp的网络请求框架:Retrofit。

Retrofit采用注解的方式进行配置相关信息,如地址,请求头,请求方式等等,另外又添加了Gson解析库的接口,接入流行的框架Rx,因为提供了配置基础设置的接口,因此存在良好的扩展性。

Retrofit的基础配置
Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(url)
//                .addConverterFactory(FastJsonConverterFactory.create())
//                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .client(httpClient.addInterceptor(interceptor).addNetworkInterceptor(netInterceptor).build())
                .build();

其中,addConverterFactory方法是用来配置Gson解析库,addCallAdapterFactory方法是用来添加Rx的适配器,通过client可以来配置基础内容,如拦截器(配置统一的请求头,获取指定的相应头),缓存配置等等。

通过retrofit.create(Class clazz)获取网络接口,clazz为Interface类型,Interface中采用注解的方式去请求网络,方式如下:
GET请求方式:

@Headers("namev:alue")
// @Headers({"key:value","key:value"})
@GET("URL")
Call<ResponseBody> getConnection(@Query("param") String param);

GET请求方式(用来Encode):

@GET("URL")
Call<ResponseBody> getConnection(@QueryMap(encode = true) Map<String, String> param);

POST请求方式(JSON请求体):

@POST("URL")
Call<ResponseBody> getConnection(@Body("param") Object p1);

POST请求方式(键值对):

@POST("URL")
Call<ResponseBody> getConnection(@FieldMap Map<String, String> params);

ResponseBody是未采用ConverterFactory
结果,因此需要通过API手动解析;而采用ConverterFactory之后,则可以将ResponseBody自动解析为指定的Object,eg:User:

@GET("URL")
Call<User> getConnection(@Query("param") String param);

因此我们只需要建立java类:

public class HttpUtil{

    publi Retrofit mRetrofit

    public HttpUtil(String baseUrl, Interceptor interceptor){
        OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
        mRetrofit = new Retrofit.Builder()
            .baseUrl(baseUrl)
//          .addConverterFactory(JsonConverterFactory.create())
            .client(httpClient.addInterceptor(interceptor).builder())
            .build();
    }

    public <T> T getServer(Class<T> clazz){
        return mRetrofit.create(clazz);
    }
}
public interface UserServer{

    @GET("URL")
Call<ResponseBody> getConnection(@Query("param") String param);

// @GET("URL")
// Call<User> getConnection(@Query("param") String param);


}
Retrofit的基础使用

使用步骤:通过配置addConverterFactory,我们就能直接通过接口调用得到json解析的返回值,否则会返回Call,需要手动处理网络请求,通过

同步:call.execute().body().string();
异步:call.enqueue(new Callback(){...});

获取网络响应:

ResponseBody  response = new HttpUtil("http://baidu.com",new Interceptor(){
    @Override
    public Response intercept(Chain chain) throws IOException {
        return chain.proceed(chain.request());
    }
}).create(UserServer.class).getConnection("param");

Rx简介

初步了解Rx

Rx是ReactiveX-响应式编程的简称,是一个函数库或者是开源框架。可以参考ReactiveX了解他的一些基本概念。

接下来Rx的结合使用:

在Retrofit的简介中,我们提到有一个addCallAdapterFactory的基本配置,是用来做Rx的桥接器使用的。通过该设置,我们的Retrofit代码接口就可以华丽的变身为:

public interface UserServer{

 @GET("URL")
 Observable<User> getConnection(@Query("param") String param);

}

也就是说,我们顺利的建立了可观测对象(Observables),通过Observables提供的Api,可以对它进行类似于工厂的自动化生产一样的链式操作,大量的减轻了我们的代码编写工作和阅读维护工作。尤其在异步线程的处理和对原数据组合变化上,更是为我们提供了便利的处理机制。

小结:

关于Rx,更多的使用方式在官网上都有对应的API讲解,在这里就不再赘述了,我们只需要记住几个关键点:

1. Observable:可观测对象
2. Operators: 操作符API的总称
3. Scheduler: 线程

Demo讲解

demo地址:RxRetrofitFrameWork

思路详解:

Retrofit的核心还是okhttp,因此很我们对Retrofit的基本设置也其实操作到了okhttp。针对于不同的业务,网络请求大致有几点要求,总结如下:

1. 常用的信息头,如:网络状态、系统类型以及版本、令牌......
2. 缓存类型的设定:如服务器判别式缓存响应,无网络状态响应等等
3. 信息传输方式如Gzip的格式的特殊化处理
4. log日志的打印

如果还有更多的通用要求,欢迎留言。

因此针对以上几点,我们需要配置不同的拦截器去处理这件事情:
通过addInterceptor添加的Interceptor主要是用于处理请求的,在Response intercept(Chain chain)方法中,我们能够添加统一信息头;而通过addNetworkInterceptor添加的Interceptor主要是用于处理由网络请求得到的非缓存结果的响应,也就是说,如果我们得到的是缓存响应,则不会经过由addNetworkInterceptor添加的Interceptor处理,只会通过addInterceptor添加的Interceptor处理。另外设置缓存目录和大小,设置响应失败的重试策略,也是根据业务需要去设定。因此,我们将这里的封装做为最底层的支持,提供网络请求器,生成请求句柄:

public class HttpManager {

    private Retrofit mRetrofit;
    private OkHttpClient mHttpClient;
    private NetServer mNetServer;

    public HttpManager(String url, Interceptor interceptor, Interceptor netInterceptor){
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        builder.cache(new Cache(new File(NetApplication.getInstance().getApplicationContext().getCacheDir(), "caches"), 1024 * 1024 * 100));
        mHttpClient = builder.addInterceptor(interceptor).addNetworkInterceptor(netInterceptor).retryOnConnectionFailure(true).build();
        mRetrofit = new Retrofit.Builder()
                .baseUrl(url)
                .client(mHttpClient)
                .build();
        mNetServer = mRetrofit.create(NetServer.class);
    }

    public NetServer getServer(){
        return mNetServer;
    }
}

接下来是业务层的相关配置:

public class NetProxy {

    private HttpManager mManger;
    private String BASE_URL = "";

    public NetProxy(){
        mManger = new HttpManager(BASE_URL, new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {
                Request originalRequest = chain.request();
                Request.Builder builder = originalRequest.newBuilder();
                // HttpUrl originalHttpUrl = original.url();
                // String queryString = originalHttpUrl.encodeQuery();  // 获取url中的参数部分
                // String path = originalHttpUrl.url().getPath();       // 获取相对地址
                // Buffer buffer = new Buffer();
                // builder.body().writeTo(buffer);
                // String requestContent = buffer.readUtf8();  // 用于post请求获取form表单内容
                builder.addHeader("key", "value");
                builder.addHeader("Accept-Encoding", "gzip");
                Request request = builder.build();
                return chain.proceed(request);
            }
        }, new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {
                Request request = chain.request();
                Response response = chain.proceed(request);
                Response.Builder builder = response.newBuilder();
                if (response.header("Content-Encoding", "").contains("gzip")){
                    BufferedSource bufferedSource = Okio.buffer(new GzipSource(response.body().source()));
                    String temStr = bufferedSource.readUtf8();
                    bufferedSource.close();
                    ResponseBody body = ResponseBody.create(MediaType.parse("application/json"), temStr);
                    builder.body(body);
                }else{
                    BufferedSource bufferedSource = Okio.buffer(response.body().source());
                    String temStr =bufferedSource.readUtf8();
                    bufferedSource.close();
                    ResponseBody body = ResponseBody.create(MediaType.parse("application/json"), temStr);
                    builder.body(body);
                }
                return builder.build();
            }
        });
    }

    public NetServer getNetServer(){
        return mManger.getServer();
    }
}

一个商业级别的App通常是有着大量的接口Api的,因此当接口越多时,越难以维护。因此我们可以利用FieldMapQueryMap进行封装处理,统一成一个请求接口,传递不同的参数值,因此我们的NetServer如下:

public interface NetServer {

    @GET
    Call<ResponseBody> getRequest(@Url String url, @QueryMap Map<String, String> map);

    @FormUrlEncoded
    @POST
    Call<ResponseBody> postRequest(@Url String url, @QueryMap Map<String, String> queryMap, @FieldMap Map<String, String> postMap);
}

这里没有文件的上传,欢迎提供代码进行补全。

每个Api都有着不同的请求参数长度,请求参数类型和请求地址,因此我们将这些内容整合为动态的参数对象,组成url,map的形式,方便我们接口类型的统一化管理。

现在我们的网络请求句柄创建好了,底层相应的配置也做好了,现在需要开启我们的请求过程。在这里注意,为什么没有选择RxAdapter和JSONConvertFactory,第一是因为如果使用了JSONConvertFactory,我们的返回类型则不是统一的Call<ResponseBody>,而是指定的Bean;第二是因为很有可能,我们需要在IO线程处理一些信息,如果使用了RxAdapter则我们通过接口就直接创建了一个完整的Observable,不利于代码的添加。

创建监听器和协议:

public interface NetResultCallback<E> {

    void onStart();

    void onSuccess(E data);

    void onFailed(int code, String msg);

    void cancel();
}
public class BaseServiceResult<T> {

    public int ret;
    public String msg;
    public T data;

    @Override
    public String toString() {
        return "BaseServiceResult{" +
                "ret=" + ret +
                ", msg='" + msg + '\'' +
                ", data=" + data +
                '}';
    }
}
public interface ErrorCode {

    int CODE_OK = 0;
    int CODE_TIME_OUT = -5000;
    int CODE_NET_ERROR = -5001;
    int CODE_RESPONSE_EMPTY = -5002;
}

补全网络请求过程:

public void excute(final String mUrl, final Map<String, String> mQueryMap, final Map<String, String> mPostMap, final MethodType mMethodType, final Class mClazz){
 Observable.create(new Observable.OnSubscribe<BaseServiceResult<T>>() {
            @Override
            public void call(Subscriber<? super BaseServiceResult<T>> subscriber) {
                Call<ResponseBody> responseBody = new NetProxy(). getNetServer().getRequest(mUrl, mQueryMap);
//              Call<ResponseBody> responseBody = new NetProxy().getNetServer().postRequest(mUrl, mPostMap, mQueryMap);
                try {
                    String strJSON = responseBody.execute().body().string();
                    BaseServiceResult<T> baseServiceResult = JSON.<BaseServiceResult<T>>parseObject(strJSON, BaseServiceResult.class);
                    if (baseServiceResult.data != null) {
                        if (baseServiceResult.data instanceof JSONObject) {
                            baseServiceResult.data = JSON.parseObject(((JSONObject) baseServiceResult.data).toJSONString(), mClazz);
                        } else if (baseServiceResult.data instanceof JSONArray) {
                            baseServiceResult.data = (T) JSON.parseArray(((JSONArray) baseServiceResult.data).toJSONString(), mClazz);
                        }
                     }
                     subscriber.onNext(baseServiceResult);
                     subscriber.onCompleted();
                 } catch (Exception e) {
                     e.printStackTrace();
                     subscriber.onError(e);
                 }
            }
        }).subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(getSubscrobe());
}
private Subscriber<BaseServiceResult<T>> getSubscrobe(final NetResultCallback<T> mCallback){
        Subscriber<BaseServiceResult<T>> mSubscriber = new Subscriber<BaseServiceResult<T>>() {

            @Override
            public void onStart() {
                super.onStart();
            }

            @Override
            public void onCompleted() {
            }

            @Override
            public void onError(Throwable e) {
                if (mCallback != null) {
                    mCallback.onFailed(ErrorCode.CODE_TIME_OUT, NetApplication.getInstance().getString(R.string.connect_time_out));
                    Log.e(TAG, "onError: " + e.getMessage());
                }
            }

            @Override
            public void onNext(BaseServiceResult<T> tBaseServiceResult) {
                if (mCallback != null) {
                    if (tBaseServiceResult == null){
                        mCallback.onFailed(ErrorCode.CODE_RESPONSE_EMPTY, NetApplication.getInstance().getString(R.string.connect_time_out));
                        return;
                    }
                    Log.i(TAG, "onNext: " + tBaseServiceResult.toString());
                    if (tBaseServiceResult.ret == ErrorCode.CODE_OK) {
                        mCallback.onSuccess(tBaseServiceResult.data);
                    }else{
                        mCallback.onFailed(tBaseServiceResult.ret, tBaseServiceResult.msg);
                    }
                }
            }
        };
        return mSubscriber;

现在基本流程已经跑通,网络部分的基础已经搭建好,然而这样的执行代码还是有着大量重复的感觉,因此我们需要对执行代码进行二次封装,由上面的方法来看,我们发现就相当于是一次下厨,准备好了原材料如:mUrl,mCallback,mClazz等等,就能够直接执行,因此我们将这些准备和执行视为一个整体,具备了基本属性和基本行为动作,顺便参照我们Rx的链式模式,我们封装如下:

public class NetProcessor<T> {

    private NetResultCallback<T> mCallback;
    private Map<String, String> mQueryMap;
    private Map<String, String> mPostMap;
    private String mUrl;
    private Class<T> mClazz;
    private @MethodType int mMethodType;
    private boolean mNeedRetry = true;
    private Subscriber<BaseServiceResult<T>> mSubscriber;
    private NetServer mServer;
    private static final String TAG = "NetProcessor";

    public static <T> NetProcessor<T> get(){
        NetProcessor<T> netProcessor = new NetProcessor<T>();
        return netProcessor;
    }

    public static <T> NetProcessor<T> post(){
        NetProcessor<T> netProcessor = new NetProcessor<T>();
        netProcessor.mPostMap = new HashMap<String, String>();
        return netProcessor;
    }

    private NetProcessor(){
        mQueryMap = new HashMap<>();
        mServer = Controller.getInstance().getmNetProxy().getNetServer();
    }

    public NetProcessor<T> putParam(String key, String value) {
        mQueryMap.put(key, value);
        return this;
    }

    public NetProcessor<T> postParam(String key, String value){
        if (mPostMap == null){
            synchronized (this){
                mPostMap = new HashMap<String, String>();
            }
        }
        mPostMap.put(key, value);
        return this;
    }

    public NetProcessor<T> onQueryMap(Map<String, String> queryMap) {
        this.mQueryMap.putAll(queryMap);
        return this;
    }

    public NetProcessor<T> onPostMap(Map<String, String> postMap) {
        if (mPostMap == null){
            mPostMap.putAll(postMap);
        }
        return this;
    }

    public NetProcessor<T> onUrl(String url) {
        this.mUrl = url;
        return this;
    }

    public NetProcessor<T> onCallback(NetResultCallback<T> callback) {
        this.mCallback = callback;
        return this;
    }

    public NetProcessor<T> onClazz(Class<T> clazz){
        this.mClazz = clazz;
        return this;
    }

    public NetProcessor<T> onRetry(boolean needRetry){
        this.mNeedRetry = needRetry;
        return this;
    }

    public NetProcessor<T> excute() {
        mCallback.onStart();
        Observable.create(new Observable.OnSubscribe<BaseServiceResult<T>>() {
            @Override
            public void call(Subscriber<? super BaseServiceResult<T>> subscriber) {
                Call<ResponseBody> responseBody = null;
                switch (mMethodType){
                    case MethodType.METHOD_GET:
                        responseBody = mServer.getRequest(mUrl, mQueryMap);
                        break;
                    case MethodType.METHOD_POST:
                        responseBody = mServer.postRequest(mUrl, mPostMap, mQueryMap);
                        break;
                }
                try {
                    String strJSON = responseBody.execute().body().string();
                    BaseServiceResult<T> baseServiceResult = JSON.<BaseServiceResult<T>>parseObject(strJSON, BaseServiceResult.class);
                    if (baseServiceResult.data != null) {
                        if (baseServiceResult.data instanceof JSONObject) {
                            baseServiceResult.data = JSON.parseObject(((JSONObject) baseServiceResult.data).toJSONString(), mClazz);
                        } else if (baseServiceResult.data instanceof JSONArray) {
                            baseServiceResult.data = (T) JSON.parseArray(((JSONArray) baseServiceResult.data).toJSONString(), mClazz);
                        }
                    }
                    subscriber.onNext(baseServiceResult);
                    subscriber.onCompleted();
                } catch (Exception e) {
                    e.printStackTrace();
                    subscriber.onError(e);
                }
            }
        }).subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .retryWhen(new Func1<Observable<? extends Throwable>, Observable<?>>() {
                    @Override
                    public Observable<?> call(Observable<? extends Throwable> observable) {
                        return observable.flatMap(new Func1<Throwable, Observable<?>>() {
                            @Override public Observable<?> call(Throwable error) {
                                if (mNeedRetry) {
                                    mNeedRetry = false;
                                    // For IOExceptions, we  retry
                                    if (error instanceof IOException) {
                                        return Observable.just(null);
                                    }
                                }
                                // For anything else, don't retry
                                return Observable.error(error);
                            }
                        });
                    }
                })
                .subscribe(getSubscrobe());
        return this;
    }

    public void cancel(){
        if (mSubscriber != null && !mSubscriber.isUnsubscribed()){
            mSubscriber.unsubscribe();
            mCallback.cancel();
        }
    }

    private Subscriber<BaseServiceResult<T>> getSubscrobe(){
        mSubscriber = new Subscriber<BaseServiceResult<T>>() {

            @Override
            public void onStart() {
                super.onStart();
            }

            @Override
            public void onCompleted() {
            }

            @Override
            public void onError(Throwable e) {
                if (mCallback != null) {
                    mCallback.onFailed(ErrorCode.CODE_TIME_OUT, NetApplication.getInstance().getString(R.string.connect_time_out));
                    Log.e(TAG, "onError: " + e.getMessage());
                }
            }

            @Override
            public void onNext(BaseServiceResult<T> tBaseServiceResult) {
                if (mCallback != null) {
                    if (tBaseServiceResult == null){
                        mCallback.onFailed(ErrorCode.CODE_RESPONSE_EMPTY, NetApplication.getInstance().getString(R.string.connect_time_out));
                        return;
                    }
                    Log.i(TAG, "onNext: " + tBaseServiceResult.toString());
                    if (tBaseServiceResult.ret == ErrorCode.CODE_OK) {
                        mCallback.onSuccess(tBaseServiceResult.data);
                    }else{
                        mCallback.onFailed(tBaseServiceResult.ret, tBaseServiceResult.msg);
                    }
                }
            }
        };
        return mSubscriber;
    }

    @IntDef({MethodType.METHOD_GET, MethodType.METHOD_POST})
    public @interface MethodType {
        // GET请求
        int METHOD_GET = 0;
        // POST请求
        int METHOD_POST = 1;
    }

    private String getQuertString(){
        if (mQueryMap == null){
            return "";
        }
        List<QueryString> list = new ArrayList<>();
        QueryString query = null;
        Set<String> set = mQueryMap.keySet();
        StringBuilder queryBuilder = new StringBuilder();
        for (String key : set) {
            query = new QueryString(key, mQueryMap.get(key));
            list.add(query);
        }
        Collections.sort(list);
        int size = list.size();
        try {
            for (int i = 0; i < size; i++) {
                queryBuilder.append(list.get(i).toStringAddAnd( i == 0 ? false : true));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return queryBuilder.toString();
    }

    private String getPostString(){
        if (mPostMap == null){
            return "";
        }
        Set<String> set = mPostMap.keySet();
        StringBuilder postBuilder = new StringBuilder();
        for (String key : set) {
            try {
                postBuilder.append("&").append(key).append("=").append(URLEncoder.encode(mPostMap.get(key), "UTF-8"));
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }
        postBuilder.deleteCharAt(0);
        return postBuilder.toString();
    }

}

应用如下:

public class UserBeanModel {

    public static NetProcessor getUser(NetResultCallback<UserBean> callback){
        Map<String, String> params = new HashMap<>();
        params.put("name", "username");
        params.put("psw", "userpsw");
        return NetProcessor.<UserBean>get()
            .onCallback(callback)
            .onRetry(true)
            .onClazz(UserBean.class)
            .onUrl("/get/user")
            .onQueryMap(params)
            .excute();
    }
}

最后通过 UserBeanModel.getUser(new NetResultCallback())执行就能得到相应的结果。

关于RxJava2和XML的结合,详见Retrofit接入RxJava2的使用以及XML在Retrofit中的使用

  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值