美文网首页小技巧Android开发经验谈Android开发
第三方开源库 RxJava - Android实用开发场景

第三方开源库 RxJava - Android实用开发场景

作者: 红橙Darren | 来源:发表于2017-12-10 17:08 被阅读1485次

    到底什么情况下可以使用 RxJava ? 我们需要知道不是使用 RxJava 而是响应式编程,好吧,那到底什么时候可以响应式编程?按道理来讲,我们写任何代码都可以采用响应式编程的思想,只不过是有没有必要而已。罗列一些使用场景:

    1. 防止按钮重复点击;
    RxView.clicks(mClearContent).debounce(300, TimeUnit.MILLISECONDS)
    
    1. EditText 添加 addTextChangedListener
    RxTextView.textChanges(mUserNameEt)
    
    1. 延迟执行
    Observable.timer(3, TimeUnit.SECONDS)
    
    1. 不断轮询
    Observable.interval(3, 3, TimeUnit.SECONDS)
    
    1. 减少频繁调用
    RxTextView.textChanges(mUserNameEt).debounce(1200, TimeUnit.MILLISECONDS)
    
    1. RxPermission请求权限
    rxPermissions.request(Manifest.permission.CAMERA)
    

    2.RxPermission 源码分析

    上面的用法真的是少得可怜,可能是我也用得比较少,其实还有一些如 RxBus + RxRelay,OkHttp + RxJava + Retrofit,MVP + Dragger + RxJava 等等,但这些目前一时半会还讲不清楚,希望后面分析完 Retrofit 源码后能说清楚一些皮毛。我们还是老老实实来看看 RxPermission 的源码?不是说好讲使用怎么又讲源码,为什么非得跟源码过不去?待会后面你就知道了。先看下使用(申请相机权限):

    RxPermissions rxPermissions = new RxPermissions(this);
    rxPermissions.request(Manifest.permission.CAMERA).subscribe(new Consumer<Boolean>() {
      @Override
      public void accept(Boolean aBoolean) throws Exception {
          if(aBoolean){
            // 有权限
          }else {
            // 没权限
          }
      }
    });
    

    回想一下我们在不用任何框架的时候,去申请权限那得多少代码啊~,关键是还需要重载 Activity 的 onRequestPermissionsResult() ,都怀疑人生了。后来自己好不容易写了个注解权限框架,但是当看到 RxPermission 就弃坑了,看看怎么实现的:

        public Observable<Boolean> request(final String... permissions) {
            return Observable.just(TRIGGER).compose(ensure(permissions));
        }
    
        public <T> ObservableTransformer<T, Boolean> ensure(final String... permissions) {
            return new ObservableTransformer<T, Boolean>() {
                @Override
                public ObservableSource<Boolean> apply(Observable<T> o) {
                    return request(o, permissions)
                            // Transform Observable<Permission> to Observable<Boolean>
                            .buffer(permissions.length)
                            .flatMap(new Function<List<Permission>, ObservableSource<Boolean>>() {
                                @Override
                                public ObservableSource<Boolean> apply(List<Permission> permissions) throws Exception {
                                    if (permissions.isEmpty()) {
                                        // Occurs during orientation change, when the subject receives onComplete.
                                        // In that case we don't want to propagate that empty list to the
                                        // subscriber, only the onComplete.
                                        return Observable.empty();
                                    }
                                    // 如果有用户没有授权的权限,返回false
                                    // Return true if all permissions are granted.
                                    for (Permission p : permissions) {
                                        if (!p.granted) {
                                            return Observable.just(false);
                                        }
                                    }
                                    // 返回授权成功
                                    return Observable.just(true);
                                }
                            });
                }
            };
        }
    
        @TargetApi(Build.VERSION_CODES.M)
        private Observable<Permission> requestImplementation(final String... permissions) {
            // 根据需要申请的权限创建一个 Observable 集合
            List<Observable<Permission>> list = new ArrayList<>(permissions.length);
            // 用来存放没有授予的权限
            List<String> unrequestedPermissions = new ArrayList<>();
    
            // In case of multiple permissions, we create an Observable for each of them.
            // At the end, the observables are combined to have a unique response.
            for (String permission : permissions) {
                mRxPermissionsFragment.log("Requesting permission " + permission);
                // 把需要申请的权限加入集合
                if (isGranted(permission)) {
                    // Already granted, or not Android M
                    // Return a granted Permission object.
                    list.add(Observable.just(new Permission(permission, true, false)));
                    continue;
                }
    
                if (isRevoked(permission)) {
                    // Revoked by a policy, return a denied Permission object.
                    list.add(Observable.just(new Permission(permission, false, false)));
                    continue;
                }
    
                PublishSubject<Permission> subject = mRxPermissionsFragment.getSubjectByPermission(permission);
                // Create a new subject if not exists
                if (subject == null) {
                    unrequestedPermissions.add(permission);
                    subject = PublishSubject.create();
                    mRxPermissionsFragment.setSubjectForPermission(permission, subject);
                }
    
                list.add(subject);
            }
            // 如果有权限没有授权,去申请
            if (!unrequestedPermissions.isEmpty()) {
                String[] unrequestedPermissionsArray = unrequestedPermissions.toArray(new String[unrequestedPermissions.size()]);
                requestPermissionsFromFragment(unrequestedPermissionsArray);
            }
            return Observable.concat(Observable.fromIterable(list));
        }
        // 调用自己额外创建的 Fragment 的申请权限方法
        @TargetApi(Build.VERSION_CODES.M)
        void requestPermissionsFromFragment(String[] permissions) {
            mRxPermissionsFragment.log("requestPermissionsFromFragment " + TextUtils.join(", ", permissions));
            mRxPermissionsFragment.requestPermissions(permissions);
        }
    

    源码其实很简单,就那么几个类,我们之所以不需要在 Activity 中重写 onRequestPermissionsResult 方法了,那是因为 RxPermission 自己额外创建了一个 Fragment ,加载到了我们的 Activity 中,so easy 。

    3.RxLogin 库封装

    最后我们根据响应式编程的思想,参照 RxPermission 的源码思想,自己动手来打造一个 RxLogin 第三方登录框架。我一般都是用友盟第三方的:

    public class UserLoginActivity extends Activity implements UMAuthListener {
        private UMShareAPI mUmShareAPI;
        public static final String PLATFORM_KEY = "PLATFORM_KEY";
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            mUmShareAPI = UMShareAPI.get(this);
            mUmShareAPI.doOauthVerify(this,SHARE_MEDIA.QQ, this);
        }
    
        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
            UMShareAPI.get(this).onActivityResult(requestCode, resultCode, data);
        }
    
        @Override
        public void onStart(SHARE_MEDIA share_media) {
            
        }
    
        @Override
        public void onComplete(SHARE_MEDIA share_media, int i, Map<String, String> map) {
            // 获取参数用户信息,调用后台接口,请求登录
        }
    
        @Override
        public void onError(SHARE_MEDIA share_media, int i, Throwable throwable) {
            // 获取等三方账号信息出错
        }
    
        @Override
        public void onCancel(SHARE_MEDIA share_media, int i) {
            // 取消第三方登录
        }
    }
    

    上面这种写法,我们初级刚入门的时候一般会这么写,这样写到底行不行,也不说不行,也不说不对。但是一般我们不会直接依赖第三方(隔离),而且其实还会多出来很多方法像 onActivityResult() 、onStar()、onCancel() 等等一些我们可能都不需要或者说不想关注,但是又不得已,哎。

    下面我们自己动手写一个RxLogin,一方面不与第三方的框架直接依赖(隔离),还有一方面我们过滤掉不关心的方法,还有一方面我们项目中如果有 Retrofit 、MVP 这些那会更加完美一些,当然还有一些其他方面。需要额外新建 5 个类,5个类有点多,如果你想放弃:

    public class RxLogin implements UMAuthListener {
        private Activity activity;
        private RxLoginResult mLoginResult;
        private PublishSubject<RxLoginResult> mLoginEmitter;
        static UMAuthListener STATIC_LISTENER;
    
        private RxLogin(Activity activity){
            this.activity = activity;
            mLoginResult = new RxLoginResult();
            STATIC_LISTENER = this;
            mLoginEmitter = PublishSubject.create();
        }
    
        public Observable<RxLoginResult> doOauthVerify(final RxLoginPlatform platform) {
            mShareResult.setPlatform(platform);
            Intent intent = new Intent(activity,RxLoginActivity.class);
            intent.putExtra(PLATFORM_KEY,platform);
            activity.startActivity(intent);
            activity.overridePendingTransition(0,0);
            List<Observable<RxLoginResult>> list = new ArrayList<>(1);
            list.add(mLoginEmitter);
            return Observable.concat(list);
        }
    
        @Override
        public void onStart(SHARE_MEDIA share_media) {
    
        }
    
        @Override
        public void onComplete(SHARE_MEDIA share_media, int i, Map<String, String> map) {
            mLoginResult.setIsSucceed(true);
            mLoginResult.setUserInfo(map);
            mLoginEmitter.onNext(mLoginResult);
        }
    
        @Override
        public void onError(SHARE_MEDIA share_media, int i, Throwable throwable) {
            mLoginResult.setIsSucceed(false);
            mLoginEmitter.onNext(mLoginResult);
            throwable.printStackTrace();
        }
    
        @Override
        public void onCancel(SHARE_MEDIA share_media, int i) {
            mLoginResult.setIsSucceed(false);
            mLoginEmitter.onNext(mLoginResult);
        }
    
        static final SHARE_MEDIA platformChange(RxLoginPlatform platform){
            switch (platform){
                case Platform_QQ:
                    return SHARE_MEDIA.QQ;
                case Platform_WX:
                    return SHARE_MEDIA.WEIXIN;
            }
            return SHARE_MEDIA.WEIXIN;
        }
    
        public static RxLogin create(Activity activity){
            return new RxLogin(activity);
        }
    }
    

    看下最后的使用:

    public class UserLoginActivity extends Activity implements UMAuthListener {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            // RxLogin 使用方式如下:
            RxLogin.create(this)
                // 第三QQ登录
                .doOauthVerify(RxLoginPlatform.Platform_QQ)
                .subscribe(new Consumer<RxLoginResult>() {
                    @Override
                    public void accept(RxLoginResult rxLoginResult) throws Exception {
                    if(rxLoginResult.isSucceed()){
                        // 调用后台接口,请求登录
                    }
                }
            });
        }
    }
    

    所有分享大纲:Android进阶之旅 - 系统架构篇

    视频讲解地址:https://pan.baidu.com/s/1pKCrVeF

    相关文章

      网友评论

      • budwey:要是早关注你,我现在技术就不会这么水了。。。。:grin:

      本文标题:第三方开源库 RxJava - Android实用开发场景

      本文链接:https://www.haomeiwen.com/subject/rnlvixtx.html