Rxjava +Retrofit2
Rxjava分发使用
Observable.create(
// 自定义source
new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> emitter) throws Exception {
// 发射器.onNext
emitter.onNext("A");
}
})
// 3:subscribe订阅过程 源码分析
// ObservableCreate. subscribe
.subscribe(
// 自定义观察者
// 1:Observer
new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(String s) {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
}
Rxjava 不加 Retrofit框架的话使用为
public void rxJavaDownloadImageAction(View view) {
// 起点
Observable.just(PATH) // 内部会分发 PATH Stirng // TODO 第二步
// TODO 第三步
.map(new Function<String, Bitmap>() {
@Override
public Bitmap apply(String s) throws Exception {
URL url = new URL(PATH);
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setConnectTimeout(5000);
int responseCode = httpURLConnection.getResponseCode(); // 才开始 request
if (responseCode == HttpURLConnection.HTTP_OK) {
InputStream inputStream = httpURLConnection.getInputStream();
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
return bitmap;
}
return null;
}
})
/*.map(new Function<Bitmap, Bitmap>() {//中间可以使用加画笔水印的功能
@Override
public Bitmap apply(Bitmap bitmap) throws Exception {
Paint paint = new Paint();
paint.setTextSize(88);
paint.setColor(Color.RED);
return drawTextToBitmap(bitmap, "大家好",paint, 88 , 88);
}
})*/
// 日志记录
.map(new Function<Bitmap, Bitmap>() {
@Override
public Bitmap apply(Bitmap bitmap) throws Exception {
Log.d(TAG, "apply: 是这个时候下载了图片啊:" + System.currentTimeMillis());
return bitmap;
}
})
.compose(rxud())
// 订阅 起点 和 终点 订阅起来
.subscribe(
// 终点
new Observer<Bitmap>() {
// 订阅开始
@Override
public void onSubscribe(Disposable d) {
// 预备 开始 要分发
// TODO 第一步
progressDialog = new ProgressDialog(DownloadActivity.this);
progressDialog.setTitle("download run");
progressDialog.show();
}
// TODO 第四步
// 拿到事件
@Override
public void onNext(Bitmap bitmap) {
image.setImageBitmap(bitmap);
}
// 错误事件
@Override
public void onError(Throwable e) {
}
// TODO 第五步
// 完成事件
@Override
public void onComplete() {
if (progressDialog != null)
progressDialog.dismiss();
}
});
}
// 图片上绘制文字 加水印
private final Bitmap drawTextToBitmap(Bitmap bitmap, String text, Paint paint, int paddingLeft, int paddingTop) {
Bitmap.Config bitmapConfig = bitmap.getConfig();
paint.setDither(true); // 获取跟清晰的图像采样
paint.setFilterBitmap(true);// 过滤一些
if (bitmapConfig == null) {
bitmapConfig = Bitmap.Config.ARGB_8888;
}
bitmap = bitmap.copy(bitmapConfig, true);
Canvas canvas = new Canvas(bitmap);
canvas.drawText(text, paddingLeft, paddingTop, paint);
return bitmap;
}
Retrofit2基本使用
一、Get请求
Retrofit在使用的过程中需要定义接口层,接口层中的每个方法标识一个独立的请求,如下定义接口层ApiService
public interface ApiService {
@GET("users/list")
Call<List<User>> getUsers();
}
@Get注解作用于方法之上,表明这是一个Get请求,@Get注解的value值与Retrofit中配置的baseUrl组成完整的请求url,List<User>代表响应结果类型,下面通过Retrofit请求完成上述请求
// builder模式构建Retrofit对象
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.example.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
// 创建接口层的代理对象,内部通过动态代理创建了ApiService的代理对象
ApiService api = retrofit.create(ApiService.class);
// 执行异步请求
api.getUsers().enqueue(new Callback<List<User>>() {
@Override
public void onResponse(Call<List<User>> call, Response<List<User>> response) {
// 处理结果
}
@Override
public void onFailure(Call<List<User>> call, Throwable t) {
// 处理异常
}
});
二、动态url访问@PATH
public interface ApiService {
@GET("user/{id}")
Call<User> getUser(@Path("id") String id);
}
@Get注解中使用了{id}作为占位符,实际运行会通过方法中@Path(“id”)注解标注的参数进行替换,访问案例如下:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.example.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
ApiService api = retrofit.create(ApiService.class);
api.getUser("1").enqueue(new Callback<User>() {
@Override
public void onResponse(Call<User> call, Response<User> response) {
}
@Override
public void onFailure(Call<User> call, Throwable t) {
}
});
三、带有查询参数设置@Query的Get请求
例如我们要访问这样的url https://api.example.com/users?username=zhangsan
接口层定义如下:
public interface ApiService {
@GET("users")
Call<User> getUserByUserName(@Query("username") String username);
}
通过@Get表明了请求方式,通过@Query标注了请求的参数名,同样的也适用与Post请求,只需要将@Get注解替换为@Post即可
四、POST请求体的方式向服务器传入json字符串@Body
public interface ApiService {
@POST("users/add")
Call<List<User>> addUser(@Body User user);
}
可以看到我们通过@Body注解标注参数对象即可,而后Retrofit内部将User对象转换了json字符串传递给服务端
其他用法参照博文https://blog.csdn.net/lilinjie_blog/article/details/108569042 下面直接讲Rxjava +Retrofit2
(1)首先定义了一个接口 这里使用的是玩android的通用接口
public interface WangAndroidApi {
// 总数据
@GET("project/tree/json")
Observable<ProjectBean> getProject(); // 异步线程 耗时操作
// ITem数据
@GET("project/list/{pageIndex}/json") // ?cid=294
Observable<ProjectItem> getProjectItem(@Path("pageIndex") int pageIndex, @Query("cid") int cid); // 异步线程 耗时操作
}
(2)定义一个http工具接口类
public class HttpUtil {
private static final String TAG = "HttpUtils";
/**
* 默认 test-a环境
*/
public static String BASE_URL = "https://www.wanandroid.com/";
public static void setBaseUrl(String baseUrl) {
BASE_URL = baseUrl;
}
/**
* 根据各种配置创建出Retrofit
*
* @return 返回创建好的Retrofit
*/
public static Retrofit getOnlineCookieRetrofit() {
// OKHttp客户端
OkHttpClient.Builder httpBuilder = new OkHttpClient.Builder();
// 各种参数配置
OkHttpClient okHttpClient = httpBuilder
.addNetworkInterceptor(new StethoInterceptor())
.readTimeout(10000, TimeUnit.SECONDS)
.connectTimeout(10000, TimeUnit.SECONDS)
.writeTimeout(10000, TimeUnit.SECONDS)
.build();
return new Retrofit.Builder().baseUrl(BASE_URL)
// TODO 请求用 OKhttp
.client(okHttpClient)
// TODO 响应RxJava
// 添加一个json解析的工具
.addConverterFactory(GsonConverterFactory.create(new Gson()))
// 添加rxjava处理工具
.addCallAdapterFactory(RxJava2CallAdapterFactory.create()) //这个一定要
.build();
}
}
(3) 在Activity中获取接口实例
ApiService api = retrofit.create(ApiService.class);//对比这个
private WangAndroidApi api;
api = HttpUtil.getOnlineCookieRetrofit().create(WangAndroidApi.class);
然后获取网络数据api
/**
* TODO Retrofit+RxJava 查询 项目分类 (总数据查询)
*
* @param view
*/
public void getProjectAction(View view) {
// 获取网络API
api.getProject()
.subscribeOn(Schedulers.io()) // 上面 异步
.observeOn(AndroidSchedulers.mainThread()) // 下面 主线程
.subscribe(new Consumer<ProjectBean>() { //简便版可以new Consumer 需要回调可以new Observer
@Override
public void accept(ProjectBean projectBean) throws Exception {
Log.d(TAG, "accept: " + projectBean); // UI 可以做事情
}
});
}
/**
* TODO Retrofit+RxJava 查询 项目分类的49 去 获取项目列表数据 (Item)
*
* @param view
*/
public void getProjectListAction(View view) {
// 注意:这里的 294 是项目分类 所查询出来的数据
// 上面的项目分类会查询出:"id": 294,"id": 402,"id": 367,"id": 323,"id": 314, ...
// id 写死的
api.getProjectItem(1, 294)
// .....
.subscribeOn(Schedulers.io()) // 上面 异步
.observeOn(AndroidSchedulers.mainThread()) // 下面 主线程
.subscribe(data->{
Log.d(TAG, "getProjectListAction: " + data);
});
}
可以实际上这个id应该是先查询总数据再根据上面的id传下来的如果是这个的话写法就是以下
插入一个利用
implementation 'com.jakewharton.rxbinding2:rxbinding:2.1.1' // 操作功能防抖
使用防抖功能,适用于所有View
/**
* RxJava
* RxJs
* Rxxxxx
* RxBinding 防抖
*
* TODO 功能防抖 + 网络嵌套(这种是负面教程,嵌套的太厉害了)
* 2层嵌套
* 6层
*/
@SuppressLint("CheckResult")
private void antiShakeActon() {
// 注意:(项目分类)查询的id,通过此id再去查询(项目列表数据)
// 对那个控件防抖动?
Button bt_anti_shake = findViewById(R.id.bt_anti_shake);
RxView.clicks(bt_anti_shake)
.throttleFirst(2000, TimeUnit.MILLISECONDS) // 2秒钟之内 响应你一次
.subscribe(new Consumer<Object>() {
@Override
public void accept(Object o) throws Exception {
api.getProject() // 查询主数据
.compose(DownloadActivity.rxud())
.subscribe(new Consumer<ProjectBean>() {
@Override
public void accept(ProjectBean projectBean) throws Exception {
for (ProjectBean.DataBean dataBean : projectBean.getData()) { // 10
// 查询item数据
api.getProjectItem(1, dataBean.getId())
.compose(DownloadActivity.rxud())
.subscribe(new Consumer<ProjectItem>() {
@Override
public void accept(ProjectItem projectItem) throws Exception {
Log.d(TAG, "accept: " + projectItem); // 可以UI操作
}
});
}
}
});
}
});
}
下面使用javamap操作符可以分发多次解决这种嵌套问题
/**
* TODO 功能防抖 + 网络嵌套 (解决嵌套的问题) flatMap
*/
@SuppressLint("CheckResult")
private void antiShakeActonUpdate() {
// 注意:项目分类查询的id,通过此id再去查询(项目列表数据)
// 对那个控件防抖动?
Button bt_anti_shake = findViewById(R.id.bt_anti_shake);
RxView.clicks(bt_anti_shake)
.throttleFirst(2000, TimeUnit.MILLISECONDS) // 2秒钟之内 响应你一次
// 我只给下面 切换 异步
.observeOn(Schedulers.io())
//上面下来的 //传给下面的
.flatMap(new Function<Object, ObservableSource<ProjectBean>>() {
@Override
public ObservableSource<ProjectBean> apply(Object o) throws Exception {
return api.getProject(); // 主数据
}
})
// 第一步不能map 因为 api Observbale<Bean> TODO
/*.map(new Function<Object, ObservableSource<ProjectBean>>() {
@Override
public ObservableSource<ProjectBean> apply(Object o) throws Exception {
return api.getProject(); // 主数据;
}
})*/
//上面下来的 //传给下面的
.flatMap(new Function<ProjectBean, ObservableSource<ProjectBean.DataBean>>() {
@Override
public ObservableSource<ProjectBean.DataBean> apply(ProjectBean projectBean) throws Exception {
return Observable.fromIterable(projectBean.getData()); // 我自己搞一个发射器 发多次 10 实际上里面有多少次会循环发送几次
}
})
.flatMap(new Function<ProjectBean.DataBean, ObservableSource<ProjectItem>>() {
@Override
public ObservableSource<ProjectItem> apply(ProjectBean.DataBean dataBean) throws Exception {
return api.getProjectItem(1, dataBean.getId());
}
})
.observeOn(AndroidSchedulers.mainThread()) // 给下面切换 主线程
.subscribe(new Consumer<ProjectItem>() {
@Override
public void accept(ProjectItem projectItem) throws Exception {
// 如果我要更新UI 会报错2 不会报错1
Log.d(TAG, "accept: " + projectItem);
}
});
}
Rx思维: 响应式编程
生活中的例子:
起点(分发事件(PATH):我饿了)----------下楼-------去餐厅--------点餐----------> 终点(吃饭 消费事件)
程序中的例子:
起点(分发事件:点击登录)----------登录API-------请求服务器--------获取响应码----------> 终点(更新UI登录成功 消费事件)
起点可以分发一个数据
onNext(1);
|
|
|
flatMap 自己分发 10个数据 给下面
1 --> 多发送 10次 1+"DDD" //javaEE
|
|
|
subscribe{
1+"DDD"
1+"DDD"
1+"DDD"
1+"DDD"
1+"DDD"
1+"DDD"
1+"DDD"
1+"DDD"
1+"DDD"
1+"DDD"
下面使用
doOnNext这个操作符完成下面的实现
- do系列的作用是side effect,当onNext发生时,它被调用,不改变数据流。
- doOnNext()允许我们在每次输出一个元素之前做一些额外的事情。
* 4.一行代码写完需求流程: 从上往下
* 1.请求服务器,执行注册操作(耗时)切换异步线程
* 2.更新注册后的所有 注册相关UI - main 切换主线程
* 3.请求服务器,执行登录操作(耗时)切换异步线程
* 4.更新登录后的所有 登录相关UI - main 切换主线程
public static Retrofit createRetrofit() {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.readTimeout(10, TimeUnit.SECONDS);
builder.connectTimeout(9, TimeUnit.SECONDS);
if (BuildConfig.DEBUG) {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
builder.addInterceptor(interceptor);
}
return new Retrofit.Builder().baseUrl("http://xxxxxxx")
.client(builder.build())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
}
MyRetrofit.createRetrofit().create(IReqeustNetwor.class)
.registerAction(new RegisterRequest()) // todo 1.请求服务器注册操作 // todo 2
.subscribeOn(Schedulers.io()) // 给上面 异步
.observeOn(AndroidSchedulers.mainThread()) // 给下面分配主线程
.doOnNext(new Consumer<RegisterResponse>() { // todo 3
@Override
public void accept(RegisterResponse registerResponse) throws Exception {
// todo 2.注册完成之后,更新注册UI
}
})
// todo 3.马上去登录服务器操作
.observeOn(Schedulers.io()) // 给下面分配了异步线程
.flatMap(new Function<RegisterResponse, ObservableSource<LoginResponse>>() { // todo 4
@Override
public ObservableSource<LoginResponse> apply(RegisterResponse registerResponse) throws Exception {
Observable<LoginResponse> loginResponseObservable = MyRetrofit.createRetrofit().create(IReqeustNetwor.class)
.loginAction(new LoginReqeust());
return loginResponseObservable;
}
})
.observeOn(AndroidSchedulers.mainThread()) // 给下面 执行主线程
.subscribe(new Observer<LoginResponse>() {
// 一定是主线程,为什么,因为 subscribe 马上调用onSubscribe
@Override
public void onSubscribe(Disposable d) {
// TODO 1
progressDialog = new ProgressDialog(RequestActivity.this);
progressDialog.show();
// UI 操作
disposable = d;
}
@Override
public void onNext(LoginResponse loginResponse) { // todo 5
// TODO 4.登录完成之后,更新登录的UI
}
@Override
public void onError(Throwable e) {
}
// todo 6
@Override
public void onComplete() {
//结束
if (progressDialog != null) {
progressDialog.dismiss();
}
}
});
注意一定要关掉 Disposable
Disposable disposable;
.subscribe( // 自定义观察者 // 1:Observer 源码看看 new Observer<String>() { @Override public void onSubscribe(Disposable d) { disposable = d; } @Override public void onNext(String s) { } @Override public void onError(Throwable e) { } @Override public void onComplete() { } });
@Override protected void onDestroy() { //一定要写,不然会发现内存泄漏 super.onDestroy(); if(disposable != null){ if(!disposable.isDisposed()){ disposable.dispose(); } } }
源代码已经上传资源
https://download.csdn.net/download/u013286571/16670315