zoukankan      html  css  js  c++  java
  • Android Rx Android实战


    上一次捣蛋 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中的线程控制

  • 相关阅读:
    刨析Maven(对pom.xml配置文件常用标签的解析)
    sublime text 3 使用技巧
    CSS3之渐变
    CSS3之过渡
    定位
    Java中的正则表达式
    CSS3之转换
    CSS布局
    导航条菜单制作总结
    Transition
  • 原文地址:https://www.cnblogs.com/android-blogs/p/5816888.html
Copyright © 2011-2022 走看看