美文网首页小技巧Android知识技巧总结实用知识
Retrofit + RxJava + OkHttp 让网络请

Retrofit + RxJava + OkHttp 让网络请

作者: 依然范特稀西 | 来源:发表于2016-11-16 21:04 被阅读45314次

    最近因为手头上的工作做完了,比较闲,想着做一些优化。看到以前用的那一套网络框架添加一个请求比较麻烦,并且比较难用,所以想改造一下网络框架。现在Android 市面上很火的当然是 Retrofit+RxJava + OkHttp, 功能强大,简单易用,因此选用这套方案来改造网络库。本篇文章是对Retrofit 的基本使用方法做一些简单的介绍。后面会再写一篇 Retrofit + RxJava + OkHttp 的封装过程。以下是正文。

    简介:

    Retrofit: Retrofit是Square 公司开发的一款正对Android 网络请求的框架。底层基于OkHttp 实现,OkHttp 已经得到了google 官方的认可。Retrofit官网

    OkHttp: 也是Square 开源的网络请求库

    RxJava:RxJava 在 GitHub 主页上的自我介绍是 "a library for composing asynchronous and event-based programs using observable sequences for the Java VM"(一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库)。这就是 RxJava ,概括得非常精准。总之就是让异步操作变得非常简单。

    各自的职责:Retrofit 负责请求的数据和请求的结果,使用接口的方式呈现,OkHttp 负责请求的过程,RxJava 负责异步,各种线程之间的切换。

    RxJava + Retrofit + okHttp 已成为当前Android 网络请求最流行的方式。

    一,Retrofit 写一个网络请求

    以获取豆瓣 Top250 榜单为例,地址:https://api.douban.com/v2/movie/

    1,首先,要使用Retrofit ,你肯定需要把它的包引入,在你的build.gradle文件中添加如下配置:

     compile 'com.squareup.retrofit2:retrofit:2.1.0'//retrofit 
     compile 'com.google.code.gson:gson:2.6.2'//Gson 库 
    //下面两个是RxJava 和RxAndroid 
    compile 'io.reactivex:rxjava:1.1.0' 
    compile 'io.reactivex:rxandroid:1.1.0'  
    compile 'com.squareup.retrofit2:converter-gson:2.1.0'//转换器,请求结果转换成Model 
    compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'//配合Rxjava 使用
    

    2,创建一个Retrofit 实例,并且完成相关的配置

    public static final String BASE_URL = "https://api.douban.com/v2/movie/";
    Retrofit retrofit = new Retrofit.Builder() 
           .baseUrl(BASE_URL) 
           .addConverterFactory(GsonConverterFactory.create())
           .build();
    

    说明:配置了接口的baseUrl和一个converter,GsonConverterFactory 是默认提供的Gson 转换器,Retrofit 也支持其他的一些转换器,详情请看官网Retrofit官网

    3,创建一个 接口 ,代码如下:

    public interface MovieService { 
    
     //获取豆瓣Top250 榜单 
     @GET("top250")
     Call<MovieSubject> getTop250(@Query("start") int start,@Query("count")int count);
    
    }
    

    说明:定义了一个方法getTop250,使用get请求方式,加上@GET 标签,标签后面是这个接口的 尾址top250,完整的地址应该是 baseUrl+尾址 ,参数 使用@Query标签,如果参数多的话可以用@QueryMap标签,接收一个Map

    4,用Retrofit 创建 接口实例 MoiveService,并且调用接口中的方法进行网络请求,代码如下:

    //获取接口实例
    MovieService MovieService movieService = retrofit.create(MovieService.class); 
    //调用方法得到一个Call 
    Call<MovieSubject> call = movieService.getTop250(0,20);
     //进行网络请求 
    call.enqueue(new Callback<MovieSubject>() {
           @Override 
           public void onResponse(Call<MovieSubject> call, Response<MovieSubject> response) { 
                mMovieAdapter.setMovies(response.body().subjects);     
                mMovieAdapter.notifyDataSetChanged(); 
           } 
          @Override 
          public void onFailure(Call<MovieSubject> call, Throwable t) { 
             t.printStackTrace(); 
          } 
    });
    

    以上是异步方式请求,还有同步方式execute(),返回一个Response,代码如下:

    Response<MovieSubject> response = call.execute();
    

    以上就是用Retrofit 完成了一个网络请求,获取豆瓣top250 榜单电影,效果图如下:

    84193B9F-BBAE-4967-ADB4-F923A422AD64.png

    以上示例是用get方式完成,如果要使用post 方式,我们只需要修改一下接口中的方法定义,如下:

    public interface MovieService { 
            //获取豆瓣Top250 榜单 
           @FormUrlEncoded
           @POST("top250") 
           Call<MovieSubject> getTop250(@Field("start") int start, @Field("count") int count);
    }
    

    说明:使用POST 请求方式时,只需要更改方法定义的标签,用@POST 标签,参数标签用 @Field 或者@Body或者FieldMap,注意:使用POST 方式时注意2点,1,必须加上 @FormUrlEncoded标签,否则会抛异常。2,使用POST方式时,必须要有参数,否则会抛异常, 源码抛异常的地方如下:

    if (isFormEncoded && !gotField) { 
          throw methodError("Form-encoded method must contain at least one @Field."); 
    }
    

    以上就是一个使用Retrofit 完成一个网络请求的完整示例,其他标签使用方式请看官网Retrofit官网,官网用法也介绍的比较详细,此外,发现了一篇博客也介绍得比较详细,Retrofit用法详解

    二,配合RxJava 使用

    1, 更改定义的接口,返回值不再是一个Call ,而是返回的一个Observble.

    public interface MovieService { 
        //获取豆瓣Top250 榜单  
        @GET("top250") 
        Observable<MovieSubject> getTop250(@Query("start") int start, @Query("count")int count);
     }
    

    2,创建Retrofit 的时候添加如下代码

    addCallAdapterFactory(RxJavaCallAdapterFactory.create())
    

    3,添加转换器Converter(将json 转为JavaBean)

    addConverterFactory(GsonConverterFactory.create())
    

    4,Activity 或者 Fragment 中传入 Subscriber 建立订阅关系

    Subscription subscription = movieService.getTop250(0,20) 
    .subscribeOn(Schedulers.io()) 
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(new Subscriber<MovieSubject>() { 
    @Override
     public void onCompleted() { 
    
     } 
    @Override 
    public void onError(Throwable e) { 
    
    } 
    @Override
     public void onNext(MovieSubject movieSubject) { 
            mMovieAdapter.setMovies(movieSubject.subjects); 
            mMovieAdapter.notifyDataSetChanged(); 
       } 
    });
    

    以上是加入RxJava 后的网络请求,返回不再是一个Call ,而是一个Observable, 在Activity / Fragment 中传入一个Subscriber 建立订阅关系,就可以在 onNext 中处理结果了,RxJava 的好处是帮我处理线程之间的切换,我们可以在指定订阅的在哪个线程,观察在哪个线程。我们可以通过操作符进行数据变换。整个过程都是链式的,简化逻辑。其中FlatMap 操作符 还可以解除多层嵌套的问题。总之,RxJava 很强大,能帮我处理很多复杂的场景,如果熟练使用的话,那么能提升我们的开发效率。这里不打算讲RxJava 的内容,如果还不了解RxJava ,或者还对RxJava不熟悉的话,推荐几篇写很优秀的博客。

    1,RxJava 的经典文章,扔物线的 给 Android 开发者的 RxJava 详解
    2,关于RxJava 友好的文章
    3,关于RxJava 友好的文章-进阶

    三,加入 OkHttp 配置

    通过OkHttpClient 可以配置很多东西,比如链接超时时间,缓存,拦截器等等。代码如下:

    // 创建 OKHttpClient 
    OkHttpClient.Builder builder = new OkHttpClient.Builder(); 
         builder.connectTimeout(DEFAULT_TIME_OUT, TimeUnit.SECONDS);//连接超时时间 
         builder.writeTimeout(DEFAULT_TIME_OUT,TimeUnit.SECONDS);//写操作 超时时间 
         builder.readTimeout(DEFAULT_TIME_OUT,TimeUnit.SECONDS);//读操作超时时间 
    
      // 添加公共参数拦截器 
    BasicParamsInterceptor basicParamsInterceptor = new BasicParamsInterceptor.Builder() 
        .addHeaderParam("userName","")//添加公共参数 
        .addHeaderParam("device","") 
        .build(); 
    
     builder.addInterceptor(basicParamsInterceptor); 
    
    // 创建Retrofit
     mRetrofit = new Retrofit.Builder() 
         .client(builder.build()) 
         .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 
         .addConverterFactory(GsonConverterFactory.create()) 
         .baseUrl(ApiConfig.BASE_URL) 
         .build();
    

    以上只是配置了一些简单的项,如,连接超时时间,实际项目中,我们可能有一些公共的参数,如 ,设备信息,渠道,Token 之类的,每个接口都需要用,我们可以写一个拦截器,然后配置到OKHttpClient里,通过 builder.addInterceptor(basicParamsInterceptor) 添加,这样我们就不用每个接口都添加这些参数了。缓存也可以通过写一个拦截器来实现(后面文章再讲)。

    以上就是Retrofit+RxJava+OkHttp实现网络请求的简单演示,如果每个接口都这么写的话,代码量太多,而且不优雅。所以还需要我们封装一下,由于篇幅有限,封装放到下一篇文章。

    ** Retrofit + RxJava + OkHttp 封装已更新,请看Retrofit + RxJava + OkHttp 让网络请求变的简单-封装篇**

    参考博客:
    1,Retrofit用法详解
    2,基于Retrofit、OkHttp、Gson封装通用网络框架
    3, RxJava 与 Retrofit 结合的最佳实践

    相关文章

      网友评论

      • 豆奶不好喝:我想问下,我也是这样写的,但是不能再onnext里边更新UI,这是为什么啊?
        李楠_be99:线程不对
      • 风岫主人:写的不错,相同的数据对象可以用泛型处理吗
      • _罪:一直没用这个,今天面试突然问到了,一脸懵逼
      • duoduo7628:Call<MovieSubject> getTop250 如果我想返回字符串该怎么做呢?
        逆风的黑子:泛型写String啊
      • degrty:博主写的很清晰,点歌赞好吧
      • xiaosa_fu:没找到源码连接地址,我就想问下有人找到了MovieSubject这个类是怎么写的吗?
        honglei92:@degrty 在理 很好很强大
        xiaosa_fu:@degrty 我猪脑袋了...
        degrty:你看response返回的json格式是什么样的,写对应的类就好了啊
      • Alin_3883:BasicParamsInterceptor 无法引入是什么原因?
      • Silicon_Valley:我想问下楼主,我加入了缓存拦截器报错,cache is closed有解决方法吗
      • Hello_8cd7:你好,文章我看到你写了PayLoad这个类用于剥离数据,但是demo中并没有用到,请问这个类在哪里用到呢?
      • Hello_8cd7:能不能给个个demo地址呢。。。。
      • 68a17e0a055b:第二个配合RxJava使用中,第4步骤Activity 或者 Fragment 中传入 Subscriber 建立订阅关系,
        .subscribe(new Subscriber<MovieSubject>() {}),参数传入Subscriber对象就报错,不清楚为什么啊?
      • SnailRuns:写的很棒,对于初学者很容易懂
      • 我不是番茄请叫我西红柿:rx都2.x了
        依然范特稀西:@beyond_beyond 看错误信息好像是说冲突了,你好好检查一下呢
        beyond_beyond:你好,我添加依赖包时后安装时出现:
        Error:Execution failed for task ':app:transformResourcesWithMergeJavaResForDebug'.
        > More than one file was found with OS independent path 'META-INF/rxjava.properties'

        这是我依赖的(都是最新的):
        implementation 'com.squareup.retrofit2:retrofit:2.3.0'
        implementation 'com.google.code.gson:gson:2.8.1'
        implementation 'io.reactivex.rxjava2:rxjava:2.1.0'
        implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
        implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
        implementation 'com.squareup.retrofit2:adapter-rxjava:2.3.0'
        依然范特稀西:@dashu3344 是的
      • 46c76387ff8c:哪里可以下载源码?
        依然范特稀西:@沉默预言 https://github.com/pinguo-zhouwei/RetrofitRxJavaDemo
        46c76387ff8c:@依然范特稀西 没找到。下载的地方
        依然范特稀西:@沉默预言 看下一篇封装,里面有github的代码链接
      • 那就走吧玉二:您好,BasicParamsInterceptor这个类是需要自己创建吗,为什么引入了类库但是找不到这个类,还是说有别的需要compile的类库
        那就走吧玉二:@e10640117 在下一篇文章找到了实现类 :joy:
      • 我说今晚月光这么美你说是的:您好,我想自己写个demo,需要用到豆瓣的图片,视频,音乐什么的,但是不知道怎么用,您是怎么用的,刚我试了试您的链接,请求无效,求告知
        汤增雷:@子陌清扬 https://developers.douban.com/wiki/?title=guide
        我说今晚月光这么美你说是的: @JayZhouFan 我刚去了,个人开发者关闭了😂
        依然范特稀西:@子陌清扬 豆瓣有免费的api ,你去开放平台注册一个帐号就可以用了
      • 72c35595f71b:下一篇发出来看看吧
        依然范特稀西:@feng0413 已经发了
      • cdcdec:期待下面的封装!
        依然范特稀西:@cdc9527 谢谢支持,已更新。

      本文标题: Retrofit + RxJava + OkHttp 让网络请

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