0%

Retrofit的简单使用

一、简述

  1. 大家应该都听过了MVP+RxJava+Retrofit+Dagger2+巴拉巴拉巴拉,这篇文章主要介绍其中的Retrofit以及RxJava2与Retrofit的简单结合。
  2. Retrofit是Square公司开发的一款针对Android网络请求的框架,Retrofit2底层基于OkHttp实现的,OkHttp现在已经得到Google官方认可。
  3. 其实写不写这个我是纠结了好久的,Retrofit太高深,也从网上看了好多教程,对于菜菜的我真不敢写,但是最后还是抱着以后方便查阅的心态写了下来。
  4. 本文目前只讲了Retrofit入门,get请求,post请求,以及如何与rxjava结合,后期可能会继续完善,文中的接口除第一个入门例字外其它的两个是我简单写的放在了腾讯云的学生机上(感谢腾讯云!)。
  5. Retrofit项目地址:https://github.com/square/retrofit

二、入门例子

  1. 添加Gradle依赖

    1
    2
    3
    4
    5
    6
    7
    8
    // Retrofit
    compile 'com.squareup.retrofit2:retrofit:2.3.0'
    // Json依赖(根据需要选择)
    compile 'com.squareup.retrofit2:converter-gson:2.3.0'
    // 字符串依赖(根据需要选择)
    compile 'com.squareup.retrofit2:converter-scalars:2.3.0'
    // RxJava2支持(根据需要选择)
    compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
  2. 创建一个JavaBean(如果用字符串不需要创建,比如需要用jsoup解析节点时)

    Retrofit可以直接将Json数据解析到JavaBean中(依赖gson或其它)。

  3. 创建请求接口

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public interface ApiStores {
    //baseUrl
    String API_SERVER_URL = "http://www.weather.com.cn/";

    // @Path可以用于任何请求,拼接url地址
    // @GET表示get请求
    // 返回一个WeatherModel对象,这是我们创建的JavaBean,retrofit可以直接解析json到这里
    @GET("adat/sk/{cityId}.html")
    Call<WeatherModel> loadDataByJson(@Path("cityId") String cityIdJson);

    //返回字符串
    @GET("adat/sk/{cityId}.html")
    Call<String> loadDataByString(@Path("cityId") String cityIdString);
    }
  4. 接口调用,生成接口的实现类的实例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    private Retrofit mRetrofit;
    private ApiStores mApiStores;
    --- --- --- --- --- --- ---
    mRetrofit = new Retrofit.Builder() //01:获取Retrofit对象
    .baseUrl(ApiStores.API_SERVER_URL) //02采用链式结构绑定Base url
    // 注意:字符创解析器要放在Gson解析器前面,不然无法解析字符串
    //使用工厂模式创建字符串解析器
    .addConverterFactory(ScalarsConverterFactory.create())
    //使用工厂模式创建Gson的解析器
    .addConverterFactory(GsonConverterFactory.create())
    .build();
    //04获取API接口的实现类的实例对象
    mApiStores = mRetrofit.create(ApiStores.class);
  5. 调用接口中的业务方法

    1
    Call<WeatherModel> mModelCall = mApiStores.loadDataByJson("101190201");
  6. 使用5中的mModelCall完成异步请求

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // 异步请求
    mModelCall.enqueue(new Callback<WeatherModel>() {
    @Override
    public void onResponse(Call<WeatherModel> call, Response<WeatherModel> response) {

    if (response.body() == null) {
    setText("null");
    } else {
    setText(response.body().getWeatherinfo().toString());
    }
    }

    @Override
    public void onFailure(Call<WeatherModel> call, Throwable t) {
    Log.e(TAG, "onFailure: ", t);
    }
    });
  7. 返回字符串(String)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    Call<String> mModelCall2 = mApiStores.loadDataByString("101190201");
    mModelCall2.enqueue(new Callback<String>() {
    @Override
    public void onResponse(Call<String> call, Response<String> response) {
    if (response.body() == null) {
    setText("null");
    } else {
    setText(response.toString());
    }
    }

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

三、get请求

  1. Query

    Get方法请求参数都会以key=value的方式拼接在url后面。@query表示请求参数,如果value值可以为空的话可以设置为null。

    1
    2
    3
    4
    5
    // @get注解就表示get请求,@query表示请求参数,将会以key=value的方式拼接在url后面
    // Query非必填可以用null填充,例如:("小王子", null, 0, 3)
    @GET("GetServlet")
    Call<RequestModel> getData(@Query("name") String name,
    @Query("value") String value);
  2. QueryMap

    如果Query参数比较多,那么可以通过@QueryMap方式将所有的参数集成在一个Map统一传递,还以上文中的get请求方法为例

    1
    2
    3
    4
    5
    6
    7
    8
    @GET("GetServlet")
    Call<RequestModel> getData(@QueryMap Map<String, String> options);
    --------------------------------------------------------------
    // 调用的时候将所有的参数集合在统一的map中即可
    Map<String, String> options = new HashMap<>();
    map.put("name", "码农Mrz");
    map.put("value", "sdwfqin");
    Call<BookSearchResponse> call = mBlueService.getSearchBooks(options);
  3. Query集合

    假如你需要添加相同Key值,但是value却有多个的情况,一种方式是添加多个@query参数,还有一种简便的方式是将所有的value放置在列表中,然后在同一个@Query下完成添加,实例代码如下

    1
    2
    @GET("GetServlet")
    Call<BookSearchResponse> getSearchBooks(@Query("value") List<String> name);
  4. 异步请求

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    Call<RequestModel> call = searchApi.getData("码农Mrz", "get请求");
    call.enqueue(new Callback<RequestModel>() {
    @Override
    public void onResponse(Call<RequestModel> call, Response<RequestModel> response) {
    setText("异步请求结果: " + response.body().toString());
    Log.e(TAG, "请求头: " + response.toString());
    }

    @Override
    public void onFailure(Call<RequestModel> call, Throwable t) {
    Log.e(TAG, "onFailure: ", t);
    }
    });
  5. 同步请求

    1
    Call<RequestModel> call = searchApi.getData("码农Mrz", "get同步请求");

四、post请求

  1. Field

    Post请求需要把请求参数放置在请求体中,而非拼接在url后面

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    /**
    * Post请求需要把请求参数放置在请求体中,而非拼接在url后面
    * <p>
    * FormUrlEncode将会自动将请求参数的类型调整为application/x-www-form-urlencoded
    * FormUrlEncode不能用于get请求
    * <p>
    * field注解将每一个请求参数都存放至请求体中,还可以添加encoded参数,该参数为boolean型
    * 例如:@Field(value = "book", encoded = true) String book
    * encoded参数为true的话,key-value-pair将会被编码,即将中文和特殊字符进行编码转换
    */
    @FormUrlEncoded // @FormUrlEncoded的默认编码方式为UTF-8
    @POST("PostServlet")
    Observable<RequestModel> PostData(@Field("name") String name,
    @Field("value") String value);
  1. FieldMap

    类似于QueryMap,传递Map

    1
    2
    3
    @FormUrlEncoded
    @POST("PostServlet")
    Call<String> PostData(@FieldMap Map<String, String> fields);
  2. @Body如果Post请求参数有多个,可以封装到一个类中

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @FormUrlEncoded
    @POST("book/reviews")
    Call<String> PostData(@Body Reviews reviews);
    ------------------------------------------
    public class Reviews {
    public String book;
    public String title;
    public String content;
    public String rating;
    }
  3. 异步跟get一样,只是请求参数一样

五、rxjava+retrofit

  1. 需要添加RxJava2适配器

    1
    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
  2. 创建实例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    private Retrofit mRetrofit;
    private RequestPostApi searchApi;
    --------------------------------
    mRetrofit = new Retrofit.Builder()
    .baseUrl("http://test.sdwfqin.com/")
    .addConverterFactory(GsonConverterFactory.create())
    // RxJava2支持
    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
    .build();
    searchApi = mRetrofit.create(RequestPostApi.class);
  3. Observable请求

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    // 调用请求方法,并得到Observable实例
    Observable<RequestModel> observable = searchApi.PostData("码农Mrz", "www.sdwfqin.com");
    observable.subscribeOn(Schedulers.io()) //在io线程进行网络请求
    // 在主线程处理返回的数据
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(new Observer<RequestModel>() {
    @Override
    public void onSubscribe(@NonNull Disposable d) {
    Log.e(TAG, "onSubscribe: ");
    }

    @Override
    public void onNext(@NonNull RequestModel postModel) {
    Log.e(TAG, "onNext: " + postModel.toString());
    setText(postModel.toString());
    }

    @Override
    public void onError(@NonNull Throwable e) {
    Log.e(TAG, "onError: ", e);
    }

    @Override
    public void onComplete() {
    Log.e(TAG, "onComplete: " + "所有事件完成");
    }
    });

六、源码地址

例子源码:https://github.com/sdwfqin/AndroidSamples