前言
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
- 创建一个接口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
- 通过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) { } }); }
- 创建一个接口RequsetService
- GET方式请求Json
- 创建一个接口
@GET("top250") Call<MovieEntity> getTopMovieJson(@Query("start") int start, @Query("count") int count);
- 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
- 获取自签名证书
//未完
- 创建接口
@GET Call<String> getHttpsHtml(@Url String url);
- 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情况)
- 创建一个接口
@POST("login") Call<Object> getInfoByPost(@Body String str);
我这里Body写成String,是因为我的数据需要加密,如果不需要加载,可以直接传对象
- 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”)为例:
- 简单例子:
Call<ResponseBody> getListMethod(@Query(“page”) int page)
foo.getListMethod(1) :baseUrl /list?page=1.
- Array/Varargs例子:
Call<ResponseBody> getListMethod(@Query(“category”) String… categories)
foo.getListMethod(“bar”, “baz”) :baseUrl /list?category=bar&category=baz.
- 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}”)为例:
- 简单例子:
Call<ResponseBody> exampleMethod(@Path(“name”) String name)
foo.exampleMethod(“John”) :baseUrl /user/John.
- encoded 例子:
Call<ResponseBody> encodedMethod(@Path(“name”) String name)
foo.encodedMethod(“John+Doe”) :baseUrl /user/John%2BDoe .
- encoded = true例子:
Call<ResponseBody> encodedMethod(@Path(value=”name”, encoded=true) String name)
foo.encodedMethod(“John+Doe”) :baseUrl /user/John%+Doe .
- 简单例子:
- @QueryMap: @GET(“/search”)
-
Call<ResponseBody> exampleMethod(@QueryMap Map<String, String> filters);
foo.exampleMethod(ImmutableMap.of(“foo”, “bar”, “kit”, “kat”)), baseUrl/search?foo=bar&kit=kat.
-
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
- 简单例子:
@FormUrlEncoded @POST("/") Call<ResponseBody> example(@Field("name") String name,@Field("occupation") String occupation);
用法:foo.exampleMethod(“Bob Smith”, “President”),body:name=Bob+Smith&occupation=President.
- 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:
- 简单例子:
@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,希望能给我留言