第三方開源庫 RxJava - Android實用開發(fā)場景

到底什么情況下可以使用 RxJava ? 我們需要知道不是使用 RxJava 而是響應式編程,好吧,那到底什么時候可以響應式編程?按道理來講,我們寫任何代碼都可以采用響應式編程的思想,只不過是有沒有必要而已。羅列一些使用場景:

  1. 防止按鈕重復點擊;
RxView.clicks(mClearContent).debounce(300, TimeUnit.MILLISECONDS)
  1. EditText 添加 addTextChangedListener
RxTextView.textChanges(mUserNameEt)
  1. 延遲執(zhí)行
Observable.timer(3, TimeUnit.SECONDS)
  1. 不斷輪詢
Observable.interval(3, 3, TimeUnit.SECONDS)
  1. 減少頻繁調(diào)用
RxTextView.textChanges(mUserNameEt).debounce(1200, TimeUnit.MILLISECONDS)
  1. RxPermission請求權(quán)限
rxPermissions.request(Manifest.permission.CAMERA)

2.RxPermission 源碼分析

上面的用法真的是少得可憐,可能是我也用得比較少,其實還有一些如 RxBus + RxRelay,OkHttp + RxJava + Retrofit,MVP + Dragger + RxJava 等等,但這些目前一時半會還講不清楚,希望后面分析完 Retrofit 源碼后能說清楚一些皮毛。我們還是老老實實來看看 RxPermission 的源碼?不是說好講使用怎么又講源碼,為什么非得跟源碼過不去?待會后面你就知道了。先看下使用(申請相機權(quán)限):

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

回想一下我們在不用任何框架的時候,去申請權(quán)限那得多少代碼啊~,關(guān)鍵是還需要重載 Activity 的 onRequestPermissionsResult() ,都懷疑人生了。后來自己好不容易寫了個注解權(quán)限框架,但是當看到 RxPermission 就棄坑了,看看怎么實現(xiàn)的:

    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();
                                }
                                // 如果有用戶沒有授權(quán)的權(quán)限,返回false
                                // Return true if all permissions are granted.
                                for (Permission p : permissions) {
                                    if (!p.granted) {
                                        return Observable.just(false);
                                    }
                                }
                                // 返回授權(quán)成功
                                return Observable.just(true);
                            }
                        });
            }
        };
    }

    @TargetApi(Build.VERSION_CODES.M)
    private Observable<Permission> requestImplementation(final String... permissions) {
        // 根據(jù)需要申請的權(quán)限創(chuàng)建一個 Observable 集合
        List<Observable<Permission>> list = new ArrayList<>(permissions.length);
        // 用來存放沒有授予的權(quán)限
        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);
            // 把需要申請的權(quán)限加入集合
            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);
        }
        // 如果有權(quán)限沒有授權(quán),去申請
        if (!unrequestedPermissions.isEmpty()) {
            String[] unrequestedPermissionsArray = unrequestedPermissions.toArray(new String[unrequestedPermissions.size()]);
            requestPermissionsFromFragment(unrequestedPermissionsArray);
        }
        return Observable.concat(Observable.fromIterable(list));
    }
    // 調(diào)用自己額外創(chuàng)建的 Fragment 的申請權(quán)限方法
    @TargetApi(Build.VERSION_CODES.M)
    void requestPermissionsFromFragment(String[] permissions) {
        mRxPermissionsFragment.log("requestPermissionsFromFragment " + TextUtils.join(", ", permissions));
        mRxPermissionsFragment.requestPermissions(permissions);
    }

源碼其實很簡單,就那么幾個類,我們之所以不需要在 Activity 中重寫 onRequestPermissionsResult 方法了,那是因為 RxPermission 自己額外創(chuàng)建了一個 Fragment ,加載到了我們的 Activity 中,so easy 。

3.RxLogin 庫封裝

最后我們根據(jù)響應式編程的思想,參照 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) {
        // 獲取參數(shù)用戶信息,調(diào)用后臺接口,請求登錄
    }

    @Override
    public void onError(SHARE_MEDIA share_media, int i, Throwable throwable) {
        // 獲取等三方賬號信息出錯
    }

    @Override
    public void onCancel(SHARE_MEDIA share_media, int i) {
        // 取消第三方登錄
    }
}

上面這種寫法,我們初級剛?cè)腴T的時候一般會這么寫,這樣寫到底行不行,也不說不行,也不說不對。但是一般我們不會直接依賴第三方(隔離),而且其實還會多出來很多方法像 onActivityResult() 、onStar()、onCancel() 等等一些我們可能都不需要或者說不想關(guān)注,但是又不得已,哎。

下面我們自己動手寫一個RxLogin,一方面不與第三方的框架直接依賴(隔離),還有一方面我們過濾掉不關(guān)心的方法,還有一方面我們項目中如果有 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()){
                    // 調(diào)用后臺接口,請求登錄
                }
            }
        });
    }
}

所有分享大綱:Android進階之旅 - 系統(tǒng)架構(gòu)篇

視頻講解地址:https://pan.baidu.com/s/1pKCrVeF

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容