上一次捣蛋 RxAndroid 是今年二月份的事情了,当时 RxAndroid 还处于一个资料甚少交流难的状态,当时还特意建了一个交流群,让搞这个的人可以加进来讨论讨论,毕竟这玩意还是挺有意思的,于是到今天群里已经有 124 人。

在这里我发现了一个现象,进入这个群的小伙伴很多都是中级工程师 or 以上的水准,没有像很多 XXXXXAndroid 交流群那样,小白和伸手党一大堆(在这里没有任何贬义看待,任何人都是从小白过来,只想说明一个现象)。嗯,是的,分层了,越是接触新颖的事物、并把事物专研进去的人才会有更大的几率发现并加入到这个组织。就像很多 HR,从古老的前程无忧到拉勾、周伯通、BOSS 直聘、100offer、github、甚至知乎等等新颖且聚集大量优秀工程师的地方招人一样,因为这些地方都聚集了热爱新潮和讨论的优秀人才。以后 HR 姐姐们也可以到各大框架的讨论区去挖人了 [笑哭]。

背景


将要重构的项目是本人的一个业余项目,由于上个公司工作太忙,导致进度缓慢,到现在功能点也还没完成多少个。趁着这几天失业,好好追追进度(工作还得要找,毕竟饭还是要吃~),顺便重构一下之前考虑不周到 or 不规范的地方,在这里 RxAndroid 充当一个辅助作用,并不是每一处地方都用上场,毕竟具体问题具体分析。

正题


RxAndroid + Retrofit

登陆功能重构之前 (只用 Retrofit 做请求):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
    public void onLogin(String phone, String psw) {
mLoginPage.showProgressBar();
HttpUtils.getApiManager().login(phone, psw)
.enqueue(new Callback<LoginResponse>() {
@Override
public void onResponse(Response<LoginResponse> response, Retrofit retrofit) {
mLoginPage.hideProgressBar();
LoginResponse result = response.body();
if(result.error_code == 0){
if(saveUserInfo(result)){
Oxygen.getInstance().closeAllPopupPage();
}else{
mLoginPage.showSnackbar(" 未知错误 ");
}
}else{
mLoginPage.showSnackbar(result.error_msg);
}
} @Override
public void onFailure(Throwable t) {
mLoginPage.hideProgressBar();
handleError(t);
}
}); } private boolean saveUserInfo(LoginResponse response){
Oxygen.setUserInfo(response.data);
return Oxygen.getUserInfo().save();
}

流程大概是这样的:账号密码请求服务器 —> 服务器返回用户资料(此处仅含 accessToken 和 refreshToken)—> 保存用户资料到本地(文件保存) —> 保存成功则登陆成功,保存失败则登陆失败。

可见,我要等 UserInfo.getInstance().save() 的返回来作出判断登陆成功与否,在这里,我放了在主线程去做,显然这样是会有性能问题。

办法 2:new Thread 去做这个保存,等待返回结果,然后再回到主 Thread 去更新 UI,大概是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    private void saveUserInfo(final LoginResponse response){
new Thread(new Runnable() {
@Override
public void run() {
Oxygen.setUserInfo(response.data);
if(Oxygen.getUserInfo().save()){
((Activity)context).runOnUiThread(new Runnable() {
@Override
public void run() {
Oxygen.getInstance().closeAllPopupPage();
}
});
}else{
((Activity)context).runOnUiThread(new Runnable() {
@Override
public void run() {
mLoginPage.showSnackbar(" 未知错误 ");
}
});
}
}
}).start();
}

这样就把卡顿主线程的问题解决了,但~~~ 有没更直观、简单的方法?

RxAndroid !!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
    public void onLogin(String phone, String psw) {
HttpUtils.getApiManager().login(phone, psw)
.subscribeOn(Schedulers.io()) // 请求服务器在 io 线程
.map(new Func1<LoginResponse, String>() {
@Override
public String call(LoginResponse response) {
if(response.error_code == 0){
return saveUserInfo(response) ? "" : " 未知错误 ";
}else{
return response.error_msg;
}
}
})
.observeOn(AndroidSchedulers.mainThread()) // 指定 doOnSubscribe 在主线程,若没有 finallyDo 可不加,否则必须加上
.doOnSubscribe(new Action0() {
@Override
public void call() {
mLoginPage.showProgressBar();
}
})
.finallyDo(new Action0() {
@Override
public void call() {
mLoginPage.hideProgressBar();
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<String>() {
@Override
public void call(String result) {
if(!TextUtils.isEmpty(result)){
mLoginPage.showSnackbar(result);
}else{
Oxygen.getInstance().closeAllPopupPage();
}
}
}, new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
handleError(throwable);
}
});
} private boolean saveUserInfo(LoginResponse response){
Oxygen.setUserInfo(response.data);
return Oxygen.getUserInfo().save();
}

响应式编程,一条链式反应,有专门处理请求前、数据返回后处理、请求完成处理、异常等等的函数,还可以给它们特指专门的线程,思路清晰多了。

RxBinding

俺身边有一位朋友可能由于单身多年,手速达到惊人地步,年轻人嘛,急,按个按钮总喜欢连续猛按几下,而页面也连续弹出几个。。。

1
2
3
4
5
6
7
8
9
10
RxAdapterView.itemClickEvents(mListView)
.throttleFirst(1, TimeUnit.SECONDS)
.subscribe(new Action1<AdapterViewItemClickEvent>() {
@Override
public void call(AdapterViewItemClickEvent adapterViewItemClickEvent) {
if(mCallback != null){
mCallback.onOpenDetailPage(event.position());
}
}
});

throttleFirst 能帮我们解决手速问题,如上。
注意,用了 RxBinding 之后,它就不仅仅是一个点击事件这么简单了,它成为了一个 Observable,然而我们可以用上它的各种特异功能 duang 的一声解决问题。

事件总线,RxBus

细心的小伙伴们可能已经发现我的代码有点奇怪,不太像是在用传统的开发模式下做操作。对,我是在自己构建的一个 MVC 架构上做的,由于还不很很成熟,就先不放出来讨论,例如模块间的耦合度还是挺大的,所以我想用 RxBus 当事件总线来解耦,这个考虑的东西比较多,先写到这里,未完待续。

推荐:

一张图解释RxJava中的线程控制

Android Rx Android实战的更多相关文章

  1. 《Android NFC 开发实战详解 》简介+源码+样章+勘误ING

    <Android NFC 开发实战详解>简介+源码+样章+勘误ING SkySeraph Mar. 14th  2014 Email:skyseraph00@163.com 更多精彩请直接 ...

  2. Android ActionBar应用实战,高仿微信主界面的设计

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/26365683 经过前面两篇文章的学习,我想大家对ActionBar都已经有一个相对 ...

  3. Android 手势检测实战 打造支持缩放平移的图片预览效果(下)

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/39480503,本文出自:[张鸿洋的博客] 上一篇已经带大家实现了自由的放大缩小图 ...

  4. 《Android Studio开发实战 从零基础到App上线》资源下载和内容勘误

    转载于:https://blog.csdn.net/aqi00/article/details/73065392 资源下载 下面是<Android Studio开发实战 从零基础到App上线&g ...

  5. 【Android开发VR实战】二.播放360&#176;全景视频

    转载请注明出处:http://blog.csdn.net/linglongxin24/article/details/53924006 本文出自[DylanAndroid的博客] [Android开发 ...

  6. 【Android开发VR实战】三.开发一个寻宝类VR游戏TreasureHunt

    转载请注明出处:http://blog.csdn.net/linglongxin24/article/details/53939303 本文出自[DylanAndroid的博客] [Android开发 ...

  7. Android Animation动画实战(二):从屏幕底部弹出PopupWindow

    在这篇文章之前,我已经陆陆续续写了几篇博客,介绍了Android Animation是如何使用的,有还不明白的,可以点击查看: 1. Android Animation动画详解(一): 补间动画 2. ...

  8. Android Animation动画实战(一): 从布局动画引入ListView滑动时,每一Item项的显示动画

    前言: 之前,我已经写了两篇博文,给大家介绍了Android的基础动画是如何实现的,如果还不清楚的,可以点击查看:Android Animation动画详解(一): 补间动画 及 Android An ...

  9. 我把阿里、腾讯、字节跳动、美团等Android性能优化实战整合成了一个PDF文档

    安卓开发大军浩浩荡荡,经过近十年的发展,Android技术优化日异月新,如今Android 11.0 已经发布,Android系统性能也已经非常流畅,可以在体验上完全媲美iOS. 但是,到了各大厂商手 ...

随机推荐

  1. JS XMLHttpRequest.upload.addEventListener 传参,回调

    JS 回调函数,传参的办法. function uploadFile(t) { var fd = new FormData(); fd.append("_netLogo", doc ...

  2. webservice跨域文件,好多年前的东西,远程调用,js服务器端使用,可以远程调用

    1.clientaccesspolicy.xml <?xml version="1.0" encoding="utf-8" ?> <acces ...

  3. 转 Linux内存管理原理

    Linux内存管理原理 在用户态,内核态逻辑地址专指下文说的线性偏移前的地址Linux内核虚拟3.伙伴算法和slab分配器 16个页面RAM因为最大连续内存大小为16个页面 页面最多16个页面,所以1 ...

  4. jQuery的动画方法

    /* animate参数: 参数一:要改变的样式属性值,写成字典的形式 参数二:动画持续的时间,单位为毫秒,一般不写单位 参数三:动画曲线,默认为‘swing’,缓冲运动,还可以设置为‘linear’ ...

  5. git使用教程1-本地代码上传到github【转载】

    本篇转自博客:上海-悠悠 原文地址:http://www.cnblogs.com/yoyoketang/tag/git/ 前言 不会使用github都不好意思说自己是码农,github作为一个开源的代 ...

  6. JAVA向EXE文件尾追加配置信息,用于解决局版客户端的程序IP配置问题

    package com.demo.blog; import java.io.DataOutputStream;import java.io.File;import java.io.FileOutput ...

  7. cpp调用dll

    c++ 显示调用 其他程序dll #pragma comment(lib, "DllTest.lib") int fnDllTest(void); int c = fnDllTes ...

  8. 关于yii2 的db log 日志 错误处理errorHandler

    log 通过配置Web.config来完成 1 数据库增加 ‘前缀_log’表 2 配置Web.config 'bootstrap' => ['log'], 'components' => ...

  9. create-react-app创建项目后运行npm run eject命令报错解决办法

    最近在用create-react-app创建项目,因要配置各种组件,比如babel,antd等, 需要运行npm run eject命令把项目的配置文件暴露出来,但是还是一如既然碰到报错,因为是在本地 ...

  10. HDU 5915 The Fastest Runner Ms. Zhang (CCPC2016 长春 E题,分类讨论 + 求字典序最小的直径 + 数据结构寻找最小值)

    题目链接  CCPC2016 Changchun Problem E 题意  给定一个$n$个点$n$条边的无向图,现在从某一点$s$出发,每个点都经过一遍,最后在$t$点停止,经过的边数为$l$   ...