Retrofit2.0+RxJava初步

作者: sunbinqiang | 来源:发表于2016-08-24 09:46 被阅读1635次

    之前看了StormZhang的网络请求哪家强, 里面有详细的主流网络请求框架对比,
    最近在自己的项目中引入了Retrofit2.0, 同时配合使用RxJava,替换了原先OkHttp。

    本文对于基本的实现做了总结,也有一些碰到的问题,以及Retrofit2.0相对1.0版本的一些变化

    依赖项

    compile 'io.reactivex:rxandroid:1.2.1'
    compile 'io.reactivex:rxjava:1.1.6'
    compile 'com.squareup.retrofit2:retrofit:2.1.0'
    compile 'com.squareup.retrofit2:converter-gson:+'
    compile 'com.squareup.retrofit2:adapter-rxjava:+'
    

    可以看到, 除了RxAndroid, RxJava, Retrofit依赖,另外还有两个: converter-gson, adapter-rxjava. 下面会做详细介绍。

    定义请求接口

    通过注解的方式,为每个请求声明请求的类型(Get, Post, Delete ...) , 地址, 以及参数等, 如下:

    public interface CommentService{
        @GET("shots/{id}/comments")
        Observable<Comment[]> getComments(@Path("id") int id,
                                          @Query("page") String page);
    }
    

    这里需要注意的是, 2.0中地址格式的变化:

    Correct: Base URL: http://example.com/api/
    Endpoint: foo/bar/ Result: http://example.com/api/foo/bar/

    而1.0中Base URL最后的“/”是在Endpoint中。

    创建Retrofit实例

    Retrofit提供了Builder和工厂模式来创建对应的请求实例,如下:

    public static <T> T createRetrofitService(final Class<T> clazz) {
    
        String GET_API_URL = "https://api.dribbble.com/v1/";
    
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(GET_API_URL)
                .addConverterFactory(GsonConverterFactory.create()) 
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())  
                .build();
        return retrofit.create(clazz);
    }
    

    我们可以看到, 在build过程中,增加了GsonConverterFactory和RxJavaCallAdapterFactory, 分别是在上述引用依赖时候的内容, 下面我们来看看Retrofit提供的这两个工厂类:

    1. GsonConverterFactory
      顾名思义,它是一个Json数据转化类,其中Gson是目前应用最广泛的Json解析库,所以Retrofit引入它就是为了将数据转化封装到内部实现,也减少了我们的工作量。
      当然1.0的Retrofit还没有引入, 我们会看到1.0是使用RestAdapter来实现请求结果转化的,下面是一段官方解释:

    But in Retrofit 2.0, Converter is not included in the package anymore. You need to plug a Converter in yourself or Retrofit will be able to accept only the String result. As a result, Retrofit 2.0 doesn't depend on Gson anymore.
    If you want to accept json result and make it parse into DAO, you have to summon Gson Converter as a separate dependency.
    compile 'com.squareup.retrofit:converter-gson:2.0.0-beta2' And plug it in through addConverterFactory. Please note that RestAdapter is now also renamed to Retrofit.

    1. RxJavaCallAdapterFactory
      这个类是为了与RxJava衔接而提供的, 如果不添加这个实现, 直接使用RxJava的观察者模式,会得到如下报错:
      Unable to create call adapter for class

    进一步封装

    通过上述“定义接口”, “创建实例”, 我们已经可以实现一个完整的请求,并将结果输出, 但是, 这样的请求并不是非常灵活, 例如,如何为每个请求中添加header信息?(我们在项目中经常把token作为每次请求的必带参数),如果按照上述方法,得在每个接口中申明header参数,显然是不太合理。
    Retrofit当然也会考虑这些问题, 可以实现自定义http客户端,我们在builder之前进行自定义,代码:

    public static <T> T createRetrofitService(final Class<T> clazz) {
    
        String GET_API_URL = "https://api.dribbble.com/v1/";
        final OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
        httpClient.addInterceptor(new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {
                Request original = chain.request();
    
                Request.Builder builder = original.newBuilder()
                        .method(original.method(), original.body())
                        //添加请求头部信息
                        .header("Authorization", "Bearer " + ServiceConfig.ACCESS_TOKEN);
    
                return chain.proceed(builder.build());
            }
        });
    
        OkHttpClient okHttpClient = httpClient.build();
    
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(GET_API_URL)
                .client(okHttpClient)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .build();
        return retrofit.create(clazz);
    }
    

    这样,就实现了每次请求都带了Header信息。以此为例, 我们还可以进一步实现请求缓存等功能, 后续再更新...
    另外, RxJava的监听线程等方法也可以封装:

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

    完成请求

    有了以上的封装,以下是我在UI层调用网络请求的代码:

    ServiceFactory.toSubscribe(getObservable(), new Subscriber<Shot[]>() {
        @Override
        public void onCompleted() {
    
        }
    
        @Override
        public void onError(Throwable e) {
            requestFailed();
        }
    
        @Override
        public void onNext(Shot[] resultList) {
            requestSuccess(resultList);
        }
    });
    
    Observable<Shot[]> getObservable() {
        return ServiceFactory.createRetrofitService(
                DribService.ShotService.class).getShots(String.valueOf(mPage), mQueryMap);
    }
    

    总结

    引入了Retrofit2.0 + RxJava, 确实使整个项目结构更加清晰, 而且也省去了原先OkHttp封装的工作。下面是我自己项目的地址,里面有更加详细的内容,后续也会进一步做一些更新,例如请求缓存等内容。
    https://github.com/binqiangsun/DribbblApp
    刚刚接触Retrofit,如果上述有错误的地方,欢迎交流指正,谢谢~

    相关文章

      网友评论

      • f87b49b4cf49:我想知道 为什么我的
        o.subscribeOn(Schedulers.io())
        .unsubscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(s);
        的最后一个方法总是报红线 就是 .subscribe(s); 这个
        f87b49b4cf49:而且我一强转类型,就报参数类型错误
      • lxqljc:想问问,如果接口返回来的json是字符串,怎么解析呢?
        sunbinqiang:@孤者行知 嗯, 如果返回的结构不是json, 那就不是用gson去解析了,可以参考一下这篇文章http://wuxiaolong.me/2016/01/15/retrofit/ 直接获取response.body().string
        lxqljc: @sunbinqiang可能我表述不清楚, 我的意思是,怎么结合retrofit+rxjava+okhttp将返回的字符串直接转换成对象。上网查了好久,都没找到答案。我自己想到了解决的思路,将okhttp请求回来的字符串先截取掉最外层的双引号,就会变成标准的json了,但是貌似试着处理了一下不行,另外一个方法是接口返回标准的json,但是全部接口那边不好改,全都是以字符串的jaon格式返回的。还有一个想法是,既然是字符串,我直接转成字符串返回结果,然后再自己解析。但是不知怎么滴,报不是预期的类型String,刚刚接触,用的不熟悉,过两天再试试。
        sunbinqiang:@孤者行知 这个是gson教程里的例子: String str = gson.fromJson("\"abc\"", String.class); 应该就是你说的这种情况吧?
        https://github.com/google/gson/blob/master/UserGuide.md

      本文标题:Retrofit2.0+RxJava初步

      本文链接:https://www.haomeiwen.com/subject/fpwnsttx.html