相关内容介绍:
- 概述
- 如何使用
- 同步请求
- 异步请求
- 如何取消
- 各种路径 @Path @Query 等的如何 以及详细使用 Url 是什么样子
如何添加Converter modules 类型转换器 可以转换哪些类型
其他内容
- 自定义Gson对象
- 新的URL定义方式
- Use an Interceptor from OkHttp(okhttp 使用拦截器)
- RxJava Integration with CallAdapter(使用rxjava)
概述
- Retrofit是由Square公司出品的针对于Android和Java的类型安全的Http客户端
- Retrofit 实际上就是对okHttp的封装
较1.9 旧版本区别
新的Service定义方式,不再有同步和异步之分
Retrofit 2.0 上,只能定义一个模式,因此要简单得多。import retrofit.Call; public interface APIService { /* Retrofit 2.0 */ @POST("/list") Call<Repo> loadRepo(); }
调用同步请求,只需调用execute,而发起一个异步请求则是调用enqueue.
Call<Repo> call = service.loadRepo();
Repo repo = call.execute();
以上的代码会阻塞线程,因此你不能在安卓的主线程中调用,不然会报错 NetworkOnMainThreadException. 如果你要调用execute 方法,请在后台线程执行。
Call<Repo> call = service.loadRepo();
call.enqueue(new Callback<Repo>(){
@Override
publicvoid onResponse(Response<Repo> response){
}
@Override
publicvoid onFailure(Throwable t){
}
});
2.
取消正在进行中的业务
service 的模式变成Call的形式的原因是为了让正在进行的事务可以被取消。要做到这点,你只需调用
call.cancel()。
事务将会在之后立即被取消。
请求时 ,如果你的在baseUrl 后面没有后续的 Path 只是一个类似百度(http://www.baidu.com) 这样的一个请求,@GET 会报错 missing @GET 或者 @URL 我们可以是用这样的方式来解决(亲测可行)。
@GET("/")
Call<ResponseBody> getBaiduInfo();
retrofit 注解
方法注解,包含@GET、@POST、@PUT、@DELETE、@PATH、@HEAD、@OPTIONS、@HTTP。
标记注解,包含@FormUrlEncoded、@Multipart、@Streaming。
参数注解,包含@Query,@QueryMap、@Body、@Field,@FieldMap、@Part,@PartMap。
其他注解,@Path、@Header,@Headers、@Url
@HTTP:可以替代其他方法的任意一种(baseUrl :http://gank.io/api/)
@HTTP(method = "GET", path = "data/{type}/{num}/{page}", hasBody = false)
Call<GankTypeEntity> getGankDataByHttp(@Path("type") String type, @Path("num") int num, @Path("page") int page);
@GET 请求(baseUrl :http://gank.io/api/)
@GET("data/{type}/{num}/{page}")
Call<GankTypeEntity> getGankDataByGet(@Path("type") String type, @Path("num") int num, @Path("page") int page);
@Url : 传入一个完整的url(如:http:\www.baidu.com/) 。 会覆盖baseUrl 。适用于baseUrl不统一的情景下。
@GET
Call<ResponseBody> getBaiduInfo(@Url String url);
@Streaming:用于下载大文件(亲测可行,app内的apk下载地址,未能提供链接)
@Streaming
@GET
Call<ResponseBody> downloadFile(@Url String url);
@Query,@QueryMap:查询参数,用于GET查询,需要注意的是@QueryMap可以约定是否需要encode
@GET("users")
Call<List<GithubUser>> getUserByGroup(@Query("groupId")int groupId);
Call<List<News>> getNews((@QueryMap(encoded=true) Map<String, String> options); (未验证)
@Body:用于POST请求体,将实例对象根据转换方式转换为对应的json字符串参数,
这个转化方式是GsonConverterFactory定义的。
@POST("add")
Call<List<User>> addUser(@Body User user);
@Field,@FieldMap:Post方式传递简单的键值对,(baseUrl :http://gank.io/api/)
需要添加@FormUrlEncoded表示表单提交 否则会报错
@Field parameters can only be used with form encoding. (parameter #1)Content-Type:application/x-www-form-urlencoded
@FormUrlEncoded
@POST("add2gank")
Call<ResponseBody> postContent(@Field("url")String url,@Field("desc") String desc,@Field("who")String who,@Field("type")String type,@Field("debug")String debug);
@Part,@PartMap:用于POST文件上传
其中@Part MultipartBody.Part代表文件,@Part(“key”) RequestBody代表参数
需要添加@Multipart表示支持文件上传的表单,Content-Type: multipart/form-data
@Multipart
@POST("upload")
Call<ResponseBody> upload(@Part("description") RequestBody description, @Part MultipartBody.Part file)
// https://github.com/iPaulPro/aFileChooser/blob/master/aFileChooser/src/com/ipaulpro/afilechooser/utils/FileUtils.java
// use the FileUtils to get the actual file by uri
File file = FileUtils.getFile(this, fileUri); // create RequestBody instance from file
RequestBody requestFile =
RequestBody.create(MediaType.parse("multipart/form-data"), file); // MultipartBody.Part is used to send also the actual file name
MultipartBody.Part body =
MultipartBody.Part.createFormData("picture", file.getName(), requestFile); // add another part within the multipart request String descriptionString = "hello, this is description speaking"; RequestBody description = RequestBody.create( MediaType.parse("multipart/form-data"), descriptionString);
@Header:header处理,不能被互相覆盖,用于修饰参数,
//动态设置Header值
@GET("user")
Call<User> getUser(@Header("Authorization") String authorization)
也可以
//静态设置Header值
@Headers("Authorization: authorization")
//这里authorization就是上面方法里传进来变量的值
@GET("widget/list")Call<User> getUser()
@Headers 用于修饰方法,用于设置多个Header值:
@Headers({ "Accept: application/vnd.github.v3.full+json", "User-Agent: Retrofit-Sample-App"})
@GET("users/{username}")
Call<User> getUser(@Path("username") String username);
Gson使用
需要导入以下依赖:
compile 'com.squareup.retrofit2:converter-gson:2.3.0'
以下为代码中使用方式:
mRetrofit = new Retrofit.Builder()
.baseUrl("http://www.baidu.com/")
.client(client)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
retrofit其他
Retrofit 支持的Converter modules 列表
Gson: com.squareup.retrofit:converter-gson
Jackson: com.squareup.retrofit:converter-jackson
Moshi: com.squareup.retrofit:converter-moshi
Protobuf: com.squareup.retrofit:converter-protobuf
Wire: com.squareup.retrofit:converter-wire
Simple XML: com.squareup.retrofit:converter-simplexml
url 问题
baseUrl 必须以“/” 结尾 否则会报错
在Retrofit2.0中,我们还可以在@Url里面定义完整的Url :
@GET("http://www.baidu.com/")
Call<ResponseBody> getBaiduInfo();
这样情况下,baseUrl 会被覆盖掉
拒绝encode
okHttp 默认会对Query 的参数进行编码 , 但是某些特殊的情况,我们并不希望如此。我们可以使用以下方式
@Query(value = "tag", encoded = false) String tag
OkHttp的支持
在Retrofit 2.0中,OkHttp 是必须的,并且自动设置为了依赖。下面的代码是从Retrofit 2.0的pom文件中抓取的。你不需要再做任何事情了。
<dependencies>
<dependency>
<groupId>com.squareup.okhttp</groupId>
<artifactId>okhttp</artifactId>
</dependency> ...
</dependencies>
添加拦截器( 拦截器的具体使用后面的博客还会继续介绍 )
client = new OkHttpClient.Builder()
.retryOnConnectionFailure(true)
.addInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Log.e("testBaidu","我这里是拦截器");
Response proceed = chain.proceed(chain.request());
return proceed;
}
})
.connectTimeout(15, TimeUnit.SECONDS)
.build();
Rxjava Retrofit使用
使用Rxjava 需要导入以下依赖:
compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
下一步,在Retrofit Builder模式的列表中 调用addCallAdapterFactory:
mRetrofit = new Retrofit.Builder()
.baseUrl("http://www.baidu.com/")
.client(client)
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
RxJava 相关代码(RxJava 此处指是提及,后续还会有博客进行详细介绍)
Observable<ResponseBody> baiduInfo = manageService.getBaiduInfo();
baiduInfo
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<ResponseBody>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(ResponseBody value) {
try {
Log.e("testBaidu", value.string());
} catch (IOException e) {
}
}
@Override
public void onError(Throwable e) {
Log.e("testBaidu","error ");
}
@Override
public void onComplete() {
Log.e("testBaidu", "onComplete");
}
});
注意如果需要访问网络
, 则 Schedulers.io 是必须的。否则就会报错。