Retrofit2.0实践记录

前言

Type-safe HTTP client for Android and Java by Square, Inc.

官网:http://square.github.io/retrofit/

API:http://square.github.io/retrofit/2.x/retrofit/

参考:http://gank.io/post/56e80c2c677659311bed9841
http://blog.csdn.net/lmj623565791/article/details/51304204

简介

主要记录一下GET,POST请求,以及Query,Path等注解的理解以及使用。主要有:

  • GET方式请求String

  • GET方式请求Json

  • GET方式访问自签名网站https

  • POST方式请求Json(需要header情况)

Converter(转化器)

Converter:用于对象转化的。默认情况下,Retrofit 请求结果为responsebody型

  Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
    ResponseBody rawBody = rawResponse.body();

    // Remove the body's source (the only stateful object) so we can pass the response along.
    rawResponse = rawResponse.newBuilder()
        .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
        .build();

    int code = rawResponse.code();
    if (code < 200 || code >= 300) {
      try {
        // Buffer the entire body to avoid future I/O.
        ResponseBody bufferedBody = Utils.buffer(rawBody);
        return Response.error(bufferedBody, rawResponse);
      } finally {
        rawBody.close();
      }
    }

    if (code == 204 || code == 205) {
      return Response.success(null, rawResponse);
    }

    ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
    try {
      T body = serviceMethod.toResponse(catchingBody);
      return Response.success(body, rawResponse);
    } catch (RuntimeException e) {
      // If the underlying source threw an exception, propagate that rather than indicating it was
      // a runtime exception.
      catchingBody.throwIfCaught();
      throw e;
    }
  }
 T toResponse(ResponseBody body) throws IOException {
    return responseConverter.convert(body);
  }

其中 T body = serviceMethod.toResponse(catchingBody);就是将ResponseBody通过Converter转换成相应的类型

Retrofit定义好的转化器有下面几种:

Gson: com.squareup.retrofit2:converter-gson
Jackson: com.squareup.retrofit2:converter-jackson
Moshi: com.squareup.retrofit2:converter-moshi
Protobuf: com.squareup.retrofit2:converter-protobuf
Wire: com.squareup.retrofit2:converter-wire
Simple XML: com.squareup.retrofit2:converter-simplexml
Scalars (primitives, boxed, and String): com.squareup.retrofit2:converter-scalars

其中Gson,Jackson,Moshi是用来转换Json对象的
Scalars 转换基本类型和String,eg:int,boolen,byte…
Simple XML:xml
Protobuf和Wire我还没有用过。

需要自定义的看这里:http://blog.csdn.net/lmj623565791/article/details/51304204

实践

  • GET方式请求String

    1. 创建一个接口RequsetService

      /** * Created by Administrator on 2016/5/4. */
      public interface RequsetService {
          /** * https://api.douban.com/v2/movie/top250?start=0&count=10 * GET方式请求String */
          @GET("top250")
          Call<String> getTopMovieStr(@Query("start") int start, @Query("count") int count);
      
      }

      这里我response的类型是一个String,所以Call里面泛型为String

    2. 通过Retrofit完成上述请求

          /**
           * method: GET
           *
           * @Query response:String
           */
          private void getStrByGetMethod() {
              String baseUrl = "https://api.douban.com/v2/movie/";
              Retrofit retrofit = new Retrofit.Builder().baseUrl(baseUrl).addConverterFactory(ScalarsConverterFactory.create()).build();
              RequsetService requsetService = retrofit.create(RequsetService.class);
              Call<String> call = requsetService.getTopMovieStr(0, 10);
              call.enqueue(new Callback<String>() {
                  @Override
                  public void onResponse(Call<String> call, Response<String> response) {
                      Log.e(TAG, "call:" + call.toString());
                      Log.e(TAG, "response:" + response.body());
                  }
      
                  @Override
                  public void onFailure(Call<String> call, Throwable t) {
      
                  }
              });
          }
  • GET方式请求Json

    1. 创建一个接口

          @GET("top250")
          Call<MovieEntity> getTopMovieJson(@Query("start") int start, @Query("count") int count);
    2. Retrofit完成请求

          /** * method: GET * * @Query response:Gson */
          private void getJsonByGetMethod() {
              String baseUrl = "https://api.douban.com/v2/movie/";
              Retrofit retrofit = new Retrofit.Builder().baseUrl(baseUrl).addConverterFactory(GsonConverterFactory.create()).build();
              RequsetService requsetService = retrofit.create(RequsetService.class);
              Call<MovieEntity> call = requsetService.getTopMovieJson(0, 10);
              Log.e(TAG, "request:" + call.request().toString());
              call.enqueue(new Callback<MovieEntity>() {
                  @Override
                  public void onResponse(Call<MovieEntity> call, Response<MovieEntity> response) {
                      tvRequset.setText(response.body().toString());
                      Log.e(TAG, "response:" + response.body().toString());
                  }
      
                  @Override
                  public void onFailure(Call<MovieEntity> call, Throwable t) {
      
                  }
              });
          }
  • GET方式访问自签名网站https

    1. 获取自签名证书
      //未完
    2. 创建接口

      @GET
      Call<String> getHttpsHtml(@Url String url);
      
    3. Retrofit完成请求

       /** * method: GET * @Url * response:String */
          private void getHttpsHtml(){
              InputStream[] inputStream = new InputStream[]{new Buffer().writeUtf8(CER_WIFI).inputStream()};
              SSLSocketFactory sslSocketFactory = HttpsUtils.getSslSocketFactory(inputStream, null, null);
      
              OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
              httpClient.sslSocketFactory(sslSocketFactory);
              OkHttpClient client = httpClient.build();
      
              String baseUrl = "https://www.wifi4.cn/wifi/yyhuang/";
              Retrofit retrofit = new Retrofit.Builder().baseUrl(baseUrl).addConverterFactory(ScalarsConverterFactory.create()).client(client).build();
              RequsetService requsetService = retrofit.create(RequsetService.class);
              Call<String> call = requsetService.getHttpsHtml("BC96802F9960");
              Log.e(TAG, "request:" + call.request().toString());
              call.enqueue(new Callback<String>() {
                  @Override
                  public void onResponse(Call<String> call, Response<String> response) {
                      Log.e(TAG, "call:" + call.toString());
                      Log.e(TAG, "response:" + response.body());
                  }
      
                  @Override
                  public void onFailure(Call<String> call, Throwable t) {
                      Log.e(TAG, "onFailure call:" + call.toString());
                      Log.e(TAG, "onFailure response:" + t.toString());
                  }
              });
          }
  • POST方式请求Json(需要header情况)

    1. 创建一个接口

      @POST("login")
      Call<Object> getInfoByPost(@Body String str);

      我这里Body写成String,是因为我的数据需要加密,如果不需要加载,可以直接传对象

    2. Retrofit完成请求

       /** * POST * @Body */
      
          private void loginByPostMethod() {
              OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
              httpClient.addInterceptor(new Interceptor() {
                  @Override
                  public okhttp3.Response intercept(Chain chain) throws IOException {
                      Request original = chain.request();
      
                      Request request = original.newBuilder()
                              .header("ver", "V3.0.6")
                              .header("ctype", "0")
                              .method(original.method(), original.body())
                              .build();
      
                      return chain.proceed(request);
                  }
              });
      
              OkHttpClient client = httpClient.build();
              Retrofit retrofit = new Retrofit.Builder()
                      .baseUrl("http://xxxx:11203/")
                      .addConverterFactory(GsonConverterFactory.create())
                      .client(client)
                      .build();
              RequsetService requsetService = retrofit.create(RequsetService.class);
              String body = "xxx";
              Call<Object> call = requsetService.getInfoByPost(body);
              Log.e(TAG, "url:" + call.request().url());
              call.enqueue(new Callback<Object>() {
                  @Override
                  public void onResponse(Call<Object> call, Response<Object> response) {
                      // tvRequset.setText(response.body().toString());
                      Log.e(TAG, "response:" + response.body());
                  }
      
                  @Override
                  public void onFailure(Call<Object> call, Throwable t) {
      
                  }
              });
          }
      

注解

  • @Query (询问):Query 作为符号“?”,然后再将Query 的参数拼接到Url,value转换成String,null忽略。以@GET(“/list”)为例:

    1. 简单例子

       Call<ResponseBody> getListMethod(@Query(“page”) int page) 

      foo.getListMethod(1) :baseUrl /list?page=1.

    2. Array/Varargs例子

      Call<ResponseBody> getListMethod(@Query(“category”) String… categories) 

      foo.getListMethod(“bar”, “baz”) :baseUrl /list?category=bar&category=baz.

    3. encoded = true例子

       Call<ResponseBody> getListMethod(@Query(value=”foo”, encoded=true) String foo) 

      foo.getListMethod(“foo+bar”) :baseUrl /list?foo=foo+bar.

  • @Path(路径):请求的URL可以根据使用的方法替换块和参数进行动态更新。替换块是由{ 和 } 环绕的字母数字字符串构成,而相应的参数必须用 @Path 注解标注,同时要求注解的参数使用相同的字符串,以@GET(“/user/{name}”)为例:

    1. 简单例子

      Call<ResponseBody> exampleMethod(@Path(“name”) String name) 

      foo.exampleMethod(“John”) :baseUrl /user/John.

    2. encoded 例子

       Call<ResponseBody> encodedMethod(@Path(“name”) String name) 

      foo.encodedMethod(“John+Doe”) :baseUrl /user/John%2BDoe .

    3. encoded = true例子

      Call<ResponseBody> encodedMethod(@Path(value=”name”, encoded=true) String name) 

      foo.encodedMethod(“John+Doe”) :baseUrl /user/John%+Doe .

  • @QueryMap: @GET(“/search”)

    1. Call<ResponseBody> exampleMethod(@QueryMap Map<String, String> filters); 

      foo.exampleMethod(ImmutableMap.of(“foo”, “bar”, “kit”, “kat”)), baseUrl/search?foo=bar&kit=kat.

    2. Call<ResponseBody> exampleMethod(@QueryMap(encoded=true) Map<String, String> filters); 

      foo.exampleMethod(ImmutableMap.of(“foo”, “foo+bar”)), baseUrl/search?foo=foo+bar.

  • @Body: 声明一个对象当作 HTTP 请求体, @POST/PUT (“users/new”),用于POST/PUT请求

    • @POST("users/new")
      Call<User> createUser(@Body User user);
  • @FormUrlEncoded: application/x-www-form-urlencoded方式提交form-encoded 数据(表单数据),请求类似于下面这样:

    • POST http://www.example.com HTTP/1.1
      Content-Type: application/x-www-form-urlencoded;charset=utf-8
      
      title=test&sub%5B%5D=1&sub%5B%5D=2&sub%5B%5D=3

      首先,Content-Type 被指定为 application/x-www-form-urlencoded;其次,提交的数据按照 key1=val1&key2=val2 的方式进行编码,key 和 val 都进行了 URL 转码。了解其他提交方式:未完。

  • @Field: 一般用于表单的方式传递键值对,多用于POST

    1. 简单例子

      @FormUrlEncoded @POST("/") Call<ResponseBody> example(@Field("name") String name,@Field("occupation") String occupation);

      用法:foo.exampleMethod(“Bob Smith”, “President”),body:name=Bob+Smith&occupation=President.

    2. Array/Varargs例子

      @FormUrlEncoded @POST(“/list”) Call<ResponseBody> exampleMethod(@Field(“name”) String… names); 

      用法:foo.exampleMethod(“Bob Smith”, “Jane Doe”),body:name=Bob+Smith&name=Jane+Doe.

  • @FieldMap

    1. 简单例子

       @FormUrlEncoded @POST("/things") Call<ResponseBody> things(@FieldMap Map<String, String> fields); ;

      用法:foo.things(ImmutableMap.of(“foo”, “bar”, “kit”, “kat”), request body :foo=bar&kit=kat.

  • @Headers: 设置静态的 header,header 不能互相覆盖。

    •  @Headers("Cache-Control: max-age=640000")
       @GET("/")
       @Headers({
         "X-Foo: Bar",
         "X-Ping: Pong"
       })
       @GET("/")
  • @Header: 更新一个请求的 header,必须给 @Header 提供相应的参数,如果参数的值为空 header 将会被忽略.


    • @GET("/") Call<ResponseBody> foo(@Header("Accept-Language") String lang);
  • @Multipart: multipart/form-data方式提交multipart数据,请求类似于下面这样:,(上传文件)

    • POST http://www.example.com HTTP/1.1
      Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryrGKCBY7qhFd3TrwA
      
      ------WebKitFormBoundaryrGKCBY7qhFd3TrwA
      Content-Disposition: form-data; name="text"
      
      title
      ------WebKitFormBoundaryrGKCBY7qhFd3TrwA
      Content-Disposition: form-data; name="file"; filename="chrome.png"
      Content-Type: image/png
      
      PNG ... content of chrome.png ...
      ------WebKitFormBoundaryrGKCBY7qhFd3TrwA--
  • @Part: 一般用于上传文件

    • @Multipart @POST("/") Call<ResponseBody> example(@Part MultipartBody.Part photo,@Part("description") String description,@Part(value = "image", encoding = "8-bit") RequestBody image);

      eg:

      File file = new File(Environment.getExternalStorageDirectory(), "icon.png");
      RequestBody photoRequestBody = RequestBody.create(MediaType.parse("image/png"), file);
      MultipartBody.Part photo = MultipartBody.Part.createFormData("photos", "icon.png", photoRequestBody);
      Call<ResponseBody> call = example(photo, RequestBody.create(null, "abc"), photoRequestBody );
  • @PartMap: 一般用于多文件上传

    • @Multipart @POST("/upload") Call<ResponseBody> upload(@Part("file") RequestBody file,@PartMap Map<String, RequestBody> params);
      File file = new File(Environment.getExternalStorageDirectory(), "messenger_01.png");
              RequestBody photo = RequestBody.create(MediaType.parse("image/png", file);
      Map<String,RequestBody> photos = new HashMap<>();
      photos.put("photos\"; filename=\"icon.png", photo);
      photos.put("username",  RequestBody.create(null, "abc"));
      Call<ResponseBody> call = upload(null,photos);

代码以后再上传
第一次使用Retrofit,如果有什么问题或者BUG,希望能给我留言

你可能感兴趣的:(Retrofit2.0实践记录)