Retrofit的作用: turns your HTTP API into a Java interface.
意思就是讲请求转为java接口一样的使用方式。
1. 添加依赖
compile ‘com.squareup.retrofit2:retrofit:2.3.0’//
compile ‘com.squareup.retrofit2:converter-gson:2.3.0’//gson转换
retrofit2内置了okhttp,可以不用依赖okhttp,但是可以使用自己的okhttp设置:
Retrofit retrofit = new Retrofit.Builder()
.client(AppOkhttpClient.create())//添加我的OkhttpClient
.baseUrl(BaseUrl)
.addConverterFactory(StringResponseConverterFactory.create("utf-8"))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
Note: 这里注意的是addConverterFactory是添加数据转换器,返回的数据是什么格式的,根据这个转换器动态选择,上面的是添加我自己写的要求返回的是String的转换器。addCallAdapterFactory是添加回调适配器,上面我添加的是RxJava2回调适配器,那么请求方法界面是返回Observable,不添任何回调适配器,使用的是Call回调。
public interface ApiTestService {
@GET("/")
Call<String> fetchGithub();//不添加任何适配器,默认的是Call回调
@GET("/")
Observable<String> fetchGithub1();//添加RxJava适配器,返回的回调是Observer
}
如果使用默认的回调适配器,使用如下:
Retrofit retrofit = new Retrofit.Builder()
.client(AppOkhttpClient.create())//添加我的OkhttpClient
.baseUrl(BaseUrl)
.addConverterFactory(StringResponseConverterFactory.create("utf-8"))
.build();
ApiTestService apiTestService = retrofit.create(ApiTestService.class);
Call<String> call = apiTestService.fetchGithub();
call.enqueue(new Callback<String>() {
@Override
public void onResponse(Call<String> call, Response<String> response) {
NetLogger.log(response.body().toString());
}
@Override
public void onFailure(Call<String> call, Throwable t) {
NetLogger.log("onError:" + t.toString());
}
});
使用了RxJava回调适配器,使用如下:
ApiTestService apiTestService = retrofit.create(ApiTestService.class);
Observable<String> observable = apiTestService.fetchGithub1();
observable.subscribe(new Observer<String>() {
...
});
2.创建HTTP Java interface:
public interface RetrofitService {
@GET("Data")
Call<ClassRoomUseTimeInOneMonthBean> getRoomUseData();
}
3.获取接口进行使用
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://192.168.2.179:8004/")
.addConverterFactory(GsonConverterFactory.create())
.build();
RetrofitService service = retrofit.create(RetrofitService.class);
Call<ClassRoomUseTimeInOneMonthBean> call = service.getRoomUseData();
获取到call后进行异步请求,跟okhttp使用方式一样:
call.enqueue(new Callback<ClassRoomUseTimeInOneMonthBean>() {
...
});
注意的是,如果没有addConverterFactory会可能报以下异常,这是因为返回接口时使用了ClassRoomUseTimeInOneMonthBean数据格式返回,但是接口返回数据没有处理就进行返回,所以会报转换异常,需要添加数据转换工厂进行数据转换处理:
retrofitjava.lang.IllegalArgumentException:
Unable to create converter for c
这里可以创建自己的数据转换工厂,比如创建StringConverterFactory,将返回的数据转换为字符串数据返回:
public class StringConverterFactory extends Converter.Factory {
public static StringConverterFactory create() {
return new StringConverterFactory();
}
private StringConverterFactory() {
}
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
return new StringResponseBodyConverter();//返回响应数据转换
}
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
return new StringRequestBodyConverter();//发送请求数据转换
}
}
StringRequestBodyConverter 将请求的字符串数据写出 :
public class StringRequestBodyConverter implements Converter<String, RequestBody> {
private static final MediaType MEDIA_TYPE = MediaType.parse("application/json; charset=UTF-8");
private static final Charset UTF_8 = Charset.forName("UTF-8");
StringRequestBodyConverter() {
}
@Override public RequestBody convert(String value) throws IOException {
Buffer buffer = new Buffer();
Writer writer = new OutputStreamWriter(buffer.outputStream(), UTF_8);
writer.write(value);
writer.close();
return RequestBody.create(MEDIA_TYPE, buffer.readByteString());
}
}
StringResponseBodyConverter响应数据转换为字符串:
public class StringResponseBodyConverter implements Converter<ResponseBody, String> {
@Override
public String convert(ResponseBody value) throws IOException {
try {
return value.string();
} finally {
value.close();
}
}
}
如果我们需要转换的不是字符串,可能是一种特定格式的数据,比如StringToObjectFactory:
public class StringToObjectFactory extends Converter.Factory {
private String tag = "StringToObjectFactory";
public static StringToObjectFactory create() {
return new StringToObjectFactory();
}
private StringToObjectFactory() {
}
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
return new Converter<ResponseBody, ApiOutBean<String>>() {
@Override
public ApiOutBean<String> convert(ResponseBody value) throws IOException {
String data = value.string()+ "";
ApiOutBean<String> ob = new ApiOutBean<>();
try {//我们在这里捕捉数据转换的异常
ob = new Gson().fromJson(data, ob.getClass());
}catch (Exception e){
Logger.log(tag,""+e.toString());
Logger.log(tag,"data:"+data);
}
return ob;
}
};
}
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
return new StringRequestBodyConverter();
}
}
如果我们不捕捉异常,会回调onFail,也可以通过捕捉异常获取到具体的异常信息,比如捕捉打印出现以下异常:
StringToObjectFactory:com.google.gson.JsonSyntaxException: >java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at >line 1 column 1 path $
StringToObjectFactory:data:
这时可以通过解析获取具体的信息。
也可以使用GsonConverterFactory, 我个人觉得GsonConverterFactory隐藏的比较死,不好查看异常情况。
4. Retrofit各类请求方式:
参考来源:http://square.github.io/retrofit/
- get查询:
@GET("Data/RoomsLessonsEachDay")
Call<ClassRoomUseTimeInOneMonthBean> getRoomUseDataGuery(@Query("time") String time);
// 多参数可以用map传递
@GET("Data/RoomsLessonsEachDay")
Call<ClassRoomUseTimeInOneMonthBean> getRoomUseDataGuery(@QueryMap Map<String, String> options);
- 单纯get获取数据:
@GET("Data/RoomsLessonsEachDay")
Call<ClassRoomUseTimeInOneMonthBean> getRoomUseData();
- get指定路径参数:
@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId);
- post字符串:
@POST("R/Announce")
Call<String> addNoticeByBody(@Body String p);
- post表单:
@FormUrlEncoded
@POST("R/Announce")
Call<String> addNoticeByForm(@Field("RoomID") String RoomID, @Field("Announce") String Announce);
}
- 添加头部信息:
@Headers("Cache-Control: max-age=640000")
@GET("widget/list")
Call<List<Widget>> widgetList();
- 结合rxJava使用
依赖:
compile 'io.reactivex.rxjava2:rxjava:2.1.7'
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'//android项目可以加上这个
compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.squareup.retrofit2:converter-gson:2.3.0'
compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'//retrofit需要添加rxJava适配器
初始化时:
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(StringToObjectFactory.create())//添加数据转换工厂
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())//与rxjava绑定的适配器
.baseUrl(BASE_URL)
.build();
retrofitService:
@Headers({
"context: mobile",
"version: 4"
})
@GET("data/Rank")
Observable<ApiOutBean<String>> getResourcesRank(
, @Query("UserID") String UserID
, @Query("UserType") int UserType
, @Query("Start") String startTime
, @Query("End") String endTime);
使用:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://192.168.2.179:8004/api/")
.addConverterFactory(StringConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
RetrofitService service = retrofit.create(RetrofitService.class);
Observable<ApiOutBean<String>> o = service.getResourcesRank(...);
o.subscribe(new Observer<ApiOutBean<String>>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull ApiOutBean<String> s) {
Logger.log("onNext", "s:"+s.toString());
}
@Override
public void onError(@NonNull Throwable e) {
Logger.log("onError", "s:"+e.toString());
}
@Override
public void onComplete() {
}
});
如果StringConverterFactory里没有捕捉转换异常,会回调onError方法。