Retrofit2 的简单使用

4,159 阅读3分钟

友情链接Rx:
Rxjava2操作符(一)
Rxjava2操作符(二)
Rxjava2操作符(三)
Retrofit2介绍
demo地址:github

1. 简介

Retrofit 是一个用于 Android 和 Java 平台的类型安全的网络请求框架。Retrofit 通过将 API 抽象成 Java 接口而让我们连接到 REST web 服务变得很轻松。其实 Retrofit 已经使用很久了,但是都没有总结过,所以写下这篇文章

2. 添加gradle

compile 'com.squareup.retrofit2:retrofit:2.3.0'
//这个玩意就是用来把json变成java中的实体类
compile 'com.squareup.retrofit2:converter-gson:2.3.0' 
//retrofit底层通过okhttp操作的
compile 'com.squareup.okhttp3:okhttp:3.9.1' 
//日志拦截器
compile 'com.squareup.okhttp3:logging-interceptor:3.9.1'  
compile 'com.google.code.gson:gson:2.8.2'

3. 初始化Retrofit

  private static final String BASE_URL = "http://m2.qiushibaike.com/";
  OkHttpClient okHttpClient = new OkHttpClient.Builder()
                            // 设置超时时间
                            .connectTimeout(10000L, TimeUnit.MILLISECONDS)
                            // 设置读写时间
                            .readTimeout(10000L, TimeUnit.MILLISECONDS)
                            .build();
Retrofit retrofit=new Retrofit.Builder()
                        .baseUrl(BASE_URL)
                        .client(okHttpClient)
                         // 添加生成bean的工厂
                        .addConverterFactory(GsonConverterFactory.create())
                        .build();

4. 各种注解

4.1 http请求的方式

在我们使用中以下四个基本上已经可以包括全部的了, 尤其 get/post 两个用的比较多

  1. GET -用于资源查询
  2. POST -用于创建资源
  3. PUT -用户更新资源
  4. DELETE -用于资源删除

4.2 关于请求的注解

格式 请求方式
@GET get请求
@POST post请求
@PUT put请求
@DELETE delete请求

4.3 GET请求 使用@GET注解

  1. 定义一个接口,里面的方法是
// 这个是得到 json字符串
 @GET("/article/list/text?page=1")
    Call<ResponseBody> getNetData();
    
// 这个是得到 实体类
@GET("/article/list/text?page=1")
    Call<TextBean> getBeanData(); 
  1. 开始发送请求
    下面得到的是json字符串
//通过请求得到 Call
 Call<ResponseBody> netData = mApiService.getNetData();
 //执行请求网络操作
        netData.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                if (response.isSuccessful()) {
                    try {
                    //response.body().string() 就是我们得到的数据
                     Toast.makeText(MainActivity.this, response.body().string(), Toast.LENGTH_SHORT).show();
                        Log.i(TAG,response.body().string());
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }

            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {
                Log.e(TAG,t.toString());
            }
        });

下面得到的是 TextBean 实体类

  Call<TextBean>  beanData = mApiService.getBeanData();;
                beanData.enqueue(new Callback<MovicBean>() {

                    @Override
                    public void onResponse(Call<MovicBean> call, Response<MovicBean> response) {
                        if (response.isSuccessful()) {
                            TextBean textBean = response.body();
                            Toast.makeText(MainActivity.this, movicBean.toString(), Toast.LENGTH_SHORT).show();
                        }
                    }

                    @Override
                    public void onFailure(Call<MovicBean> call, Throwable t) {

                    }
                });

4.3.1 . 上面是简单的请求,假如我们需要动态设置页数,和每页的个数,还有类型那我们就该用到下面的方法了

  • @Query 动态设置参数
  • @Path 动态设置路径
  • @QueryMap 动态设置参数map集合

@Query

假如我们要查丑事百科的纯文, 当前查询的是第一页url是

http://m2.qiushibaike.com/article/list/text?page=1

当我们再查第二页的时候的url是

http://m2.qiushibaike.com/article/list/text?page=2

对比发现只有page的参数发生了改变,这里用@Query注解完美解决 步骤:

  • 定义接口
 @GET("/article/list/text")
   Call<TextBean> getDataByQuery(@Query("page") String page);
  • 调用接口
//可以动态设置page的页数

  Call<TextBean> beanData  = mApiService.getDataByQuery("1");
  // 开始执行
  beanData.enqueue(...);

假如我们有两个变化的参数,或者多个的时候怎么办呢?,可以写多参数,下面就是 page 和 每页的个数的组合

 @GET("/article/list/text")
 Call<TextBean> getDataByMoreQuery(@Query("page") String page,@Query("size")String size);

@QueryMap

假如我们参数过多的话,挨个写@Query有点麻烦,所以用到了 @QueryMap

 @GET("/article/list/text")
    Call<TextBean> getDataByMap(@QueryMap Map<String, String> map);

下载文件

InputStream is = response.body().byteStream();得到下载的字节流

// baseUrl 用的我的github上的一个apk,https://github.com/niezhiyang/StudyDemo/blob/master/TinkerDemo/patch.apk
 @GET()
    Call<ResponseBody> getDownload(@Url String baseUrl,@Query("raw")String raw);

@Path 动态设置路径

假如我们要查纯文 和 热门的

//纯文
http://m2.qiushibaike.com/article/list/text
//热门
http://m2.qiushibaike.com/article/list/video

4.3 POST请求 使用@POST注解

  • 场景一 登录例子 下一个接口 @FormUrlEncoded 表示表单形式提交参数 @Field 添加参数
    @POST("login")
    @FormUrlEncoded
    Call<UserBean> postLogin(@Field("username") String username, @Field("pwd") String pwd);

调用

  Call<UserBean> nzy = mApiService.postLogin("nzy", "123456");
                nzy.enqueue(...);
  • 表单上传 @Part
@Multipart
    @POST ("/avatar")
    Call<UserBean> postAvatar (@Header("Authorization") String authorization, @Part("file\"; filename=\"pp.png") RequestBody file);
  • 添加头部(比如 header) @Part
@Multipart
    @POST ()
    Call<UserBean> postHeader (@Header("header") String header);

Retrofit配合rxjava的使用

添加依赖compile'com.squareup.retrofit2:adapter-rxjava2:2.3.0'这个版本跟Retrofit版本最好一致

初始化Retrofit

 Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .client(okHttpClient)
                // 添加生成bean的工厂
                .addConverterFactory(GsonConverterFactory.create())
                //添加支持Rxjava
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build();

添加接口

 @GET("/article/list/text?page=1")
    Observable<TextBean> getBeanObservable();

调用接口

 mApiService = retrofit.create(ApiService.class);
        Observable<TextBean> observable = mApiService.getBeanObservable();
        observable.subscribe(new Consumer<TextBean>() {
            @Override
            public void accept(TextBean textBean) throws Exception {
                Intent intent = new Intent(getApplicationContext(), TextActivity.class);
                intent.putExtra("textbean", textBean);
                startActivity(intent);
            }
        });