Retrofit
Retrofit 是什么
Retrofit 是一个通过注解将 REST API 转换成 Java 接口的函数库。特点
* 要求服务端接口遵守 REST 规范
* 可以自动把返回的字符串解析成 GSON 实体
* 默认搭配 GSON 和 OkHttp 使用
* 支持 Rxjava,可以直接返回 Oservable
拼接 url
Retrofit 通过注解转换接口。主要两个部分:在 retrofit 中设置主机地址;在 Server 接口中设置方法和参数。
常用的注解:
* POST/GET 请求方式
* PATH 路径中的占位符
* Query/QueryMap 请求参数,会在 url 后面直接拼接 “?key=value&key1=vaule2…”
* Field/FieldMap 请求参数,只能在 post 中使用,且要配合 @FromUrlEncoded 使用,会把参数添加到请求体中
关于在接口中使用注解可见 https://blog.csdn.net/jasonwang18/article/details/68486709
以下代码实现了 “http://47.96.165.11:8080/ncgctest/SandPlantScreen/getAll.json?name=山” 的 url。
public interface SandplantServer {
@GET("{function}.json")
Call<String> getSandplantByName(@Path("function") String function,@Query("name") String sandplantName);
}
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://47.96.165.11:8080/ncgctest/SandPlantScreen/")
.build();
Call<String> stringCall=retrofit.create(SandplantServer.class).getSandplantByName("getAll","山");
接收回调
retrofit 接收三种方式的回调:字符串,GSON 解析的实体类,RxJava 的 Oservable 对象。在 Retrofit 中设置:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://106.3.227.33/pulamsi/")
//增加返回值为String的支持
.addConverterFactory(ScalarsConverterFactory.create())
//增加返回值为Gson的支持(以实体类返回)
.addConverterFactory(GsonConverterFactory.create())
//增加返回值为Oservable<T>的支持
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
这三种方式分别需要依赖:
compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta4'//ConverterFactory的Gson依赖包
compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0-beta4'//CallAdapterFactory的Rx依赖包
compile 'com.squareup.retrofit2:converter-scalars:2.0.0-beta4'//ConverterFactory的String依赖包
完整代码:
public interface SandplantServer {
@GET("{function}.json")
Call<String> getSandplantByName(@Path("function") String function,@Query("name") String sandplantName);
}
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://47.96.165.11:8080/ncgctest/SandPlantScreen/")
//增加返回值为String的支持
.addConverterFactory(ScalarsConverterFactory.create())
.build();
SandplantServer mSandplantServer=retrofit.create(SandplantServer.class);
Call<String> stringCall=mSandplantServer.getSandplantByName("getAll","山");
stringCall.enqueue(new Callback<String>() {
@Override
public void onResponse(Call<String> call, Response<String> response) {
Log.i("hhhhh", "onResponse: "+response.body());
}
@Override
public void onFailure(Call<String> call, Throwable t) {
Log.i("hhhhh", "onFailure: ",t);
}
});
RxJava
RxJava 是使用观察者模式来实现的一个响应式框架,用于处理异步操作。
观察者模式
以为一个 Button 设置 OnClickListener 为例,Button 是被观察者,OnClickListener 是观察者,setOnClickListener 这一动作称为订阅,OnClickListener 中的 onClick 方法为事件。
RxJava 的观察者模式
- 被观察者 Observable
- 观察者 Observer
- 订阅 subscribe()
- 事件 onNext(),onCompleted(),onError()
RxJava 内置了一个实现了 Observer 的抽象类:Subscriber 。Subscriber 中增加了两个方法 onStart() 和 unsubscribe() ,分别用于在事件发送前调用和取消订阅。
实际上,在 RxJava 的 subscribe 过程中,Observer 也总是会先被转换成一个 Subscriber 再使用。
普通使用
//观察者
final Observer<String> observer=new Observer<String>() {
//事件
@Override
public void onCompleted() {
Log.i(TAG, "onCompleted: ");
}
@Override
public void onError(Throwable e) {
Log.i(TAG, "onError: ",e);
}
@Override
public void onNext(String s) {
Log.i(TAG, "onNext: "+s);
}
};
//被观察者
Observable observable=Observable.create(new Observable.OnSubscribe() {
@Override
public void call(Object o) {
observer.onNext("1");
observer.onNext("2");
observer.onNext("3");
observer.onCompleted();
}
});
//订阅
observable.subscribe(observer);
事件变换
RxJava 的一大特点是事件变换,他可以将事件序列中的事件进行加工变换,转换成不同的事件序列,从而实现分步骤处理复杂的事务。基本原理就是通过拦截旧的事件,处理后重新发送新的事件。
ActionX 和 FuncX
ActionX 是 RxJava 的一系列接口,它只有一个方法 call(),这个方法无返回值,参数个数为 X。这个系列的方法可以被用以包装不同的无返回值的方法。通常用于包装 subscribe 中的 onNext(),onCompleted(),onError() 方法,作为一个参数传入 subscribe() 以实现不完整定义的回调,RxJava 会自动根据定义创建出 Subscriber。
FuncX 系列方法与 ActionX 相似,但是有返回值的,所以被用以包装不同的有返回值的方法。通常在事件变换的时候使用,用以返回其他类型的事件。
示例:
Observable.just("images/logo.png") // 输入类型 String
.map(new Func1<String, Bitmap>() {
@Override
public Bitmap call(String filePath) { // 参数类型 String
return getBitmapFromPath(filePath); // 返回类型 Bitmap
}
})
.subscribe(new Action1<Bitmap>() {
@Override
public void call(Bitmap bitmap) { // 参数类型 Bitmap
showBitmap(bitmap);
}
});
常用的变换:
* map() 事件对象直接变换,从一个事件转换成另一个事件
* flatMap() 把一个事件转换成一个 Observable,通过激活传入的 Observable 并把发送的事件传入新的 Observable 中并统一交给 Subscriber 。可用于一对多的转换,并可以嵌套异步的代码。
* throttleFirst() 在每次事件触发后丢弃一定时间间隔内的新的事件,可用作去抖动过滤
* zip() 有三个参数,可以把两个队列合并到一个中。
线程控制
RxJava 支持异步的关键就是线程调度器 Scheduler ,RxJava 中的调度器:
* Schedulers.immediate() 在本线程执行
* Schedulers.newThread() 新建线程执行
* Schedulers.io() 读写使用的线程,在一个线程池中使用空闲线程进行,网络请求一般也使用此线程
* Schedulers.computation() 计算使用的线程,使用一个跟 CPU 核数相同的线程池
* AndroidSchedulers.mainThread() Android 专用的主线程
在 Observable 中使用 subscribeOn 和 observeOn 分别设置事件产生的线程和事件消费的线程。subscribeOn 只能调用一次,而 observeOn 可以调用多次,在变换之前调用可以指定每次变换所在的线程。
Rxjava+Retrofit
依赖
implementation 'com.squareup.retrofit2:retrofit:2.4.0'
implementation 'com.squareup.retrofit2:converter-scalars:2.4.0'//ConverterFactory的String依赖包
implementation 'com.squareup.retrofit2:converter-gson:2.4.0'//ConverterFactory的Gson依赖包
implementation 'com.squareup.retrofit2:adapter-rxjava:2.4.0'//CallAdapterFactory的Rx依赖包
implementation 'io.reactivex:rxjava:1.1.0'//Rx的包
implementation 'io.reactivex:rxandroid:1.1.0'//Rx的包
public class DataBean<T> {
private String msg;
private int code;
private List<T> data;
}
public class SandplantBean {
private String name;
private int userId;
}
public class UserBean {
private int userId;
private String userName;
private String realName;
private String mobile;
}
public interface SandplantServer {
@GET("SandPlantScreen/{function}.json")
Observable<DataBean<SandplantBean>> getSandplantObservable(@Path("function") String function,@Query("name") String sandplantName);
@GET("sysUserScreen/find.json")
Observable<UserBean> getUser(@Query("userId") int userId);
}
private void getSandPlantOwner() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://47.96.165.11:8080/ncgctest/")
//增加返回值为String的支持
.addConverterFactory(ScalarsConverterFactory.create())
//增加返回值为Gson的支持(以实体类返回)
.addConverterFactory(GsonConverterFactory.create())
//增加返回值为Oservable<T>的支持
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
final SandplantServer mSandplantServer = retrofit.create(SandplantServer.class);
mSandplantServer.getSandplantObservable("getAll", "山")
//把一个 DataBean 转换成一个 List<SandplantBean>
.map(new Func1<DataBean<SandplantBean>, List<SandplantBean>>() {
@Override
public List<SandplantBean> call(DataBean<SandplantBean> sandplantBeanDataBean) {
return sandplantBeanDataBean.getData();
}
})
//把一个 List<SandplantBean> 转换成一个 SandplantBean 队列
.flatMap(new Func1<List<SandplantBean>, Observable<SandplantBean>>() {
@Override
public Observable<SandplantBean> call(List<SandplantBean> sandplantBeans) {
return Observable.from(sandplantBeans);
}
})
//根据 SandplantBean 获取其 UserBean,此操作需要从后台获取数据,是异步操作
.flatMap(new Func1<SandplantBean, Observable<UserBean>>() {
@Override
public Observable<UserBean> call(SandplantBean sandplantBean) {
return mSandplantServer.getUser(sandplantBean.getUserId());
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<UserBean>() {
@Override
public void call(UserBean userBean) {
if (userBean==null){
return;
}
Log.i(TAG, "call: " + userBean.toString());
}
}, new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
Log.i(TAG, "call: ",throwable);
Toast.makeText(MainActivity.this, "数据错误", Toast.LENGTH_SHORT).show();
}
});
}
以上代码实现了一下操作:
1. 从后台获取 Sandplant 信息,并解析成 DataBean
2. 从 DataBean 中获取 List
3. 把 List 转换成 SandplantBean 队列
4. 对于每个 SandplantBean 根据其 userId 从后台获取相应的 UserBean
5. 打印获取到的 UserBean 信息
参考的文章:
https://www.daidingkang.cc/2016/06/17/Retrofit2-network-framework-parsing/