RxPermissions 源碼解析之舉一反三

[toc]

RxPermissions 源碼解析

簡(jiǎn)介

RxPermissions 是基于 RxJava 開(kāi)發(fā)的用于幫助 在Android 6.0 中處理運(yùn)行時(shí)權(quán)限檢測(cè)的框架册舞。在 Android 6.0 中增加了對(duì)危險(xiǎn)權(quán)限的動(dòng)態(tài)申請(qǐng)安疗,而不是像 Android 6.0 之前的默認(rèn)全部獲取的方式。

原始動(dòng)態(tài)權(quán)限的獲取

如果按照以往的獲取權(quán)限方式的話晌纫,那么我們獲取權(quán)限一般需要有 3 個(gè)步驟昼榛,第一步是先判斷當(dāng)前是否已經(jīng)獲取到該權(quán)限了境肾;第 2 步申請(qǐng)對(duì)應(yīng)的權(quán)限;第 3 步在 Activity 或者 Fragment 中處理獲取權(quán)限的結(jié)果胆屿。具體的實(shí)現(xiàn)步驟如下:

  • step 1:判斷權(quán)限是否已經(jīng)獲取奥喻。
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                Manifest.permission.CAMERA)) {
            //用于開(kāi)發(fā)者提示用戶權(quán)限的用途
        } else {
            //申請(qǐng)權(quán)限
        }
  • step 2:申請(qǐng)權(quán)限
ActivityCompat.requestPermissions(MainActivity.this,
                                    new String[]{Manifest.permission.CAMERA},
                                    REQUEST_CAMERA);
  • step 3:結(jié)果處理
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
        @NonNull int[] grantResults) {
    // 判斷請(qǐng)求碼,確定當(dāng)前申請(qǐng)的權(quán)限
    if (requestCode == REQUEST_CAMERA) {
        //判斷權(quán)限是否申請(qǐng)通過(guò)
        if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            //授權(quán)成功
        } else {
               //授權(quán)失敗
        }
    } else {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }
}

RxPermissions 的簡(jiǎn)單使用

其實(shí) RxPermissions 的使用方式有兩種

  • 方式 1:
RxPermissions rxPermissions = new RxPermissions(MainActivity.this);
        rxPermissions
                .request(Manifest.permission.READ_EXTERNAL_STORAGE,
                        Manifest.permission.WRITE_EXTERNAL_STORAGE)//這里填寫所需要的權(quán)限
                .subscribe(new Consumer<Boolean>() {
                    @Override
                    public void accept(Boolean aBoolean) throws Exception {
                        if (aBoolean) {
                            // 通過(guò)
                        }else{
                            // 拒絕
                        }
                    }
                });
  • 方式 2:結(jié)合 RxBinding 來(lái)使用
RxPermissions rxPermissions = new RxPermissions(MainActivity.this);
// Must be done during an initialization phase like onCreate
RxView.clicks(findViewById(R.id.enableCamera))
    .compose(rxPermissions.ensure(Manifest.permission.CAMERA))
    .subscribe(granted -> {
        // R.id.enableCamera has been clicked
    });

源碼分析

整體介紹

接著我們來(lái)對(duì)這個(gè) RxPermissions 進(jìn)行一個(gè)源碼的解析非迹,但是打開(kāi)源碼的時(shí)候环鲤,我們可以發(fā)現(xiàn),這個(gè)庫(kù)里面憎兽,其實(shí)就只有 3 個(gè)類:RxPermissions冷离、RxPermissionsFragment、Permission

  • RxPermissions
    • 最主要的實(shí)現(xiàn)類纯命,利用 rxjava酒朵,為我們提供了方便權(quán)限申請(qǐng)的類
  • RxPermissionsFragment
    • 是一個(gè) fragment,主要的動(dòng)態(tài)權(quán)限獲取類
  • Permission
    • 定義的權(quán)限的 model 類

源碼分析

RxPermissions 實(shí)例創(chuàng)建

對(duì)于源碼的分析扎附,我們應(yīng)該先從簡(jiǎn)單的使用入手。下面我們可以先看看實(shí)例化 RxPermissionsFragment 的時(shí)候是做了什么结耀?

    RxPermissionsFragment mRxPermissionsFragment;

    public RxPermissions(@NonNull Activity activity) {
        mRxPermissionsFragment = getRxPermissionsFragment(activity);
    }

我們可以看到留夜,上面的代碼中,實(shí)例化 RxPermissionsFragment 的時(shí)候图甜,里面先創(chuàng)建了一個(gè) RxPermissionsFragment 的實(shí)例碍粥。我們?cè)俳又?getRxPermissionsFragment 這個(gè)方法的實(shí)現(xiàn)。

    private RxPermissionsFragment getRxPermissionsFragment(Activity activity) {
        //  查找 RxPermissionsFragment 是否已經(jīng)被添加了
        RxPermissionsFragment rxPermissionsFragment = findRxPermissionsFragment(activity);
        boolean isNewInstance = rxPermissionsFragment == null;
        if (isNewInstance) {
            rxPermissionsFragment = new RxPermissionsFragment();
            FragmentManager fragmentManager = activity.getFragmentManager();
            fragmentManager
                    .beginTransaction()
                    .add(rxPermissionsFragment, TAG)
                    .commitAllowingStateLoss();
            fragmentManager.executePendingTransactions();
        }
        return rxPermissionsFragment;
    }

在 getRxPermissionsFragment() 這個(gè)方法中黑毅,首先是先查找當(dāng)前是否已經(jīng)添加了這個(gè) rxPermissionsFragment 的實(shí)例嚼摩,如果已經(jīng)添加,那么直接返回已經(jīng)添加的實(shí)例,如果沒(méi)有添加過(guò)的話枕面,那么就重新再創(chuàng)建一個(gè) RxPermissionsFragment 實(shí)例并提交愿卒;

    private RxPermissionsFragment findRxPermissionsFragment(Activity activity) {
        return (RxPermissionsFragment) activity.getFragmentManager().findFragmentByTag(TAG);
    }

到此,rxPermissionsFragment 的實(shí)例化已經(jīng)完成潮秘,接著我們需要看看 request 這個(gè)方法中實(shí)現(xiàn)了什么琼开。

request 方法

    public Observable<Boolean> request(final String... permissions) {
        return Observable.just(TRIGGER).compose(ensure(permissions));
    }
    static final Object TRIGGER = new Object();

從上面的代碼中,我們可以看到枕荞,request 方法中需要傳入的參數(shù)是一個(gè) 權(quán)限的數(shù)組柜候,返回值是 Observable<Boolean> 對(duì)象。Observable.just(TRIGGER) 是快捷創(chuàng)建一個(gè) Observable 的方式躏精,由于 TRIGGER 是一個(gè)空的 Object 對(duì)象渣刷,所以 TRIGGER 就是一個(gè)占位符而已,Observable.just(TRIGGER) 創(chuàng)建的是一個(gè) Observable<Object>,之后通過(guò) compose 將 Observable<Object> 轉(zhuǎn)化為 Observable<Boolean> 并返回矗烛。在 compose 中需要的參數(shù)是一個(gè) ObservableTransformer辅柴,那么我們接著看 ensure() 這個(gè)方法。

ensure(permissions);

public <T> ObservableTransformer<T, Boolean> ensure(final String... permissions) {
        // 創(chuàng)建一個(gè)Transformer對(duì)象返回
        return new ObservableTransformer<T, Boolean>() {
            @Override
            public ObservableSource<Boolean> apply(Observable<T> o) {
                //request(o, permissions) 方法返回 Observable<Permission> 對(duì)象
                return request(o, permissions)
                        // 將 Observable<Permission> 轉(zhuǎn)換為 Observable<Boolean>高诺,在這里會(huì)等待所有的權(quán)限都返回了一次性發(fā)射數(shù)據(jù)碌识。
                        .buffer(permissions.length)
                        .flatMap(new Function<List<Permission>, ObservableSource<Boolean>>() {
                            @Override
                            public ObservableSource<Boolean> apply(List<Permission> permissions) throws Exception {
                                // 如果permissions為空那么直接返回Observable.empty();
                                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();
                                }
                                // Return true if all permissions are granted.
                                for (Permission p : permissions) {
                                    if (!p.granted) {
                                        return Observable.just(false);
                                    }
                                }
                                return Observable.just(true);
                            }
                        });
            }
        };
    }

在 ensure 的這個(gè)方法中,最終會(huì)返回的是 ObservableTransformer<T, Boolean> 對(duì)象虱而。接著我們看看 ObservableTransformer 的匿名實(shí)現(xiàn)類里面的 apply 方法筏餐,這里實(shí)現(xiàn)的就是將 Observable<Permission> 轉(zhuǎn)換為 Observable<Boolean> 的操作。我們對(duì) apply 這個(gè)方法里面的代碼進(jìn)行簡(jiǎn)化一下牡拇。

return request(o,permissions)
    .buffer(permissions.length)
    .flatMap(new Function<List<Permission>, ObservableSource<Boolean>>{});
  • request() 方法返回 Observable<Permission> 對(duì)象
  • buffer(len) 操作符將一個(gè) Observable<Permission> 變換為 Observable<List<Permission>>魁瞪,原來(lái)的 Observable 正常發(fā)射數(shù)據(jù),變換產(chǎn)生的 Observable 發(fā)射這些數(shù)據(jù)的緩存集合惠呼。buffer 將數(shù)據(jù)緩存到一個(gè)集合當(dāng)中导俘,然后在適當(dāng)(比如:所有請(qǐng)求的權(quán)限結(jié)果都返回了)的時(shí)機(jī)一起發(fā)送。
  • flatMap() 方法將 Observable<List<Permission>> 轉(zhuǎn)化為 Observable<Boolean>

request(o, permissions);

    private Observable<Permission> request(final Observable<?> trigger, final String... permissions) {
        if (permissions == null || permissions.length == 0) {
            throw new IllegalArgumentException("RxPermissions.request/requestEach requires at least one input permission");
        }
        return oneOf(trigger, pending(permissions))
                .flatMap(new Function<Object, Observable<Permission>>() {
                    @Override
                    public Observable<Permission> apply(Object o) throws Exception {
                        return requestImplementation(permissions);
                    }
                });
    }

在 request 這個(gè)方法里面剔蹋,其實(shí) oneOf() 和 pending() 方法我們可以忽略的旅薄,主要的話,我們應(yīng)該關(guān)注 requestImplementation(final String... permissions) 這個(gè)方法泣崩,在這個(gè)方法里面少梁,主要實(shí)現(xiàn)了權(quán)限的請(qǐng)求。

requestImplementation


    @TargetApi(Build.VERSION_CODES.M)
    private Observable<Permission> requestImplementation(final String... permissions) {
        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.
                // 權(quán)限已經(jīng)被同意或者不是 Android 6.0 以上版本,創(chuàng)建一個(gè) 同意的 Permission 對(duì)象。
                list.add(Observable.just(new Permission(permission, true, false)));
                continue;
            }

            if (isRevoked(permission)) {
                // 權(quán)限被拒絕崇棠,返回一個(gè) 拒絕的 Permission 對(duì)象。
                list.add(Observable.just(new Permission(permission, false, false)));
                continue;
            }

            PublishSubject<Permission> subject = mRxPermissionsFragment.getSubjectByPermission(permission);
            // 如果 subject 不存在妨马,那么創(chuàng)建一個(gè) subject挺举。
            if (subject == null) {
                unrequestedPermissions.add(permission);
                subject = PublishSubject.create();
                mRxPermissionsFragment.setSubjectForPermission(permission, subject);
            }

            list.add(subject);
        }
        
        // 還未提起申請(qǐng)的權(quán)限進(jìn)行申請(qǐng)
        if (!unrequestedPermissions.isEmpty()) {
            String[] unrequestedPermissionsArray = unrequestedPermissions.toArray(new String[unrequestedPermissions.size()]);
            requestPermissionsFromFragment(unrequestedPermissionsArray);
        }
        
        // 嚴(yán)格按照順序發(fā)射數(shù)據(jù)
        return Observable.concat(Observable.fromIterable(list));
    }

onRequestPermissionsResult()


    @TargetApi(Build.VERSION_CODES.M)
    public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        if (requestCode != PERMISSIONS_REQUEST_CODE) return;

        boolean[] shouldShowRequestPermissionRationale = new boolean[permissions.length];

        for (int i = 0; i < permissions.length; i++) {
            shouldShowRequestPermissionRationale[i] = shouldShowRequestPermissionRationale(permissions[i]);
        }

        onRequestPermissionsResult(permissions, grantResults, shouldShowRequestPermissionRationale);
    }

    void onRequestPermissionsResult(String permissions[], int[] grantResults, boolean[] shouldShowRequestPermissionRationale) {
        for (int i = 0, size = permissions.length; i < size; i++) {
            log("onRequestPermissionsResult  " + permissions[i]);
            // Find the corresponding subject
            PublishSubject<Permission> subject = mSubjects.get(permissions[i]);
            if (subject == null) {
                // No subject found
                Log.e(RxPermissions.TAG, "RxPermissions.onRequestPermissionsResult invoked but didn't find the corresponding permission request.");
                return;
            }
            // 發(fā)射權(quán)限申請(qǐng)結(jié)果
            mSubjects.remove(permissions[i]);
            boolean granted = grantResults[i] == PackageManager.PERMISSION_GRANTED;
            subject.onNext(new Permission(permissions[i], granted, shouldShowRequestPermissionRationale[i]));
            subject.onComplete();
        }
    }

RxJava 操作符

Observable.just()

just 操作符是將一個(gè)對(duì)象轉(zhuǎn)化為 Observable 的操作符。這個(gè)對(duì)象可以是一個(gè)數(shù)字烘跺、字符串或者是數(shù)組對(duì)象等湘纵,是 RxJava 中快速創(chuàng)建一個(gè) Observable 對(duì)象的操作符。如果有 subscriber 訂閱的話液荸,那么會(huì)依次調(diào)用 onNext() 和 OnComplete() 方法瞻佛。所以這里只是創(chuàng)建了一個(gè) Observable 對(duì)象,方便后續(xù)的調(diào)用娇钱。

compose(Transformer)操作符

compose 操作符是對(duì) Observable 對(duì)象的整體轉(zhuǎn)化伤柄。例如:通過(guò) Transformer,我們可以將 Observable<Object> 對(duì)象轉(zhuǎn)換成 Observable<Boolean> 對(duì)象了文搂。

    public static ObservableTransformer<String,Boolean> getTransformer(){
        return new ObservableTransformer<String, Boolean>() {
            @Override
            public ObservableSource<Boolean> apply(Observable<String> upstream) {
                return upstream.flatMap(new Function<String, ObservableSource<Boolean>>() {
                    @Override
                    public ObservableSource<Boolean> apply(String s) throws Exception {
                        return Observable.just(true);
                    }
                });
            }
        };
    }

    /**
     * 線程切換
     * @return
     */
    public static <T> ObservableTransformer<T,T> getScheduler(){
        return new ObservableTransformer<T, T>() {
            @Override
            public ObservableSource<T> apply(Observable<T> upstream) {
                return upstream.subscribeOn(Schedulers.io())
                        .observeOn(AndroidSchedulers.mainThread());
            }
        };
    }
    

buffer 操作符

buffer 操作符將一個(gè) Observable 變換為另一個(gè)适刀,原來(lái)的 Observable 正常發(fā)射數(shù)據(jù),變換產(chǎn)生的 Observable 發(fā)射這些數(shù)據(jù)的緩存集合煤蹭。buffer將數(shù)據(jù)緩存到一個(gè)集合當(dāng)中笔喉,然后在適當(dāng)?shù)臅r(shí)機(jī)一起發(fā)送。
buffer(count) 以列表(List)的形式發(fā)射非重疊的緩存硝皂,每一個(gè)緩存至多包含來(lái)自原始Observable的count項(xiàng)數(shù)據(jù)(最后發(fā)射的列表數(shù)據(jù)可能少于count項(xiàng))

  • 例如:緩存 2 個(gè)數(shù)據(jù)之后常挚,再發(fā)送數(shù)據(jù)(調(diào)用 buffer(count) 函數(shù))
                Observable.just(1,2,3,4,5,6)
                        .buffer(2)
                        .subscribe(integers -> {
                            Log.i(TAG, "accept size: "+integers.size());
                            for (Integer integer : integers) {
                                Log.i(TAG, "accept: "+integer);
                            }
                        });
  • 輸出結(jié)果
2018-12-14 11:16:28.452 28126-28126/com.luwei.lwbaselib I/LwBaseActivity: accept size: 2
2018-12-14 11:16:28.452 28126-28126/com.luwei.lwbaselib I/LwBaseActivity: accept: 1
2018-12-14 11:16:28.453 28126-28126/com.luwei.lwbaselib I/LwBaseActivity: accept: 2
2018-12-14 11:16:28.453 28126-28126/com.luwei.lwbaselib I/LwBaseActivity: accept size: 2
2018-12-14 11:16:28.453 28126-28126/com.luwei.lwbaselib I/LwBaseActivity: accept: 3
2018-12-14 11:16:28.453 28126-28126/com.luwei.lwbaselib I/LwBaseActivity: accept: 4
2018-12-14 11:16:28.453 28126-28126/com.luwei.lwbaselib I/LwBaseActivity: accept size: 2
2018-12-14 11:16:28.453 28126-28126/com.luwei.lwbaselib I/LwBaseActivity: accept: 5
2018-12-14 11:16:28.453 28126-28126/com.luwei.lwbaselib I/LwBaseActivity: accept: 6
  • 例如:緩存 3 個(gè)數(shù)據(jù),再發(fā)送數(shù)據(jù)稽物,每次移動(dòng) 1 步
                Observable.just(1,2,3,4)
                        .buffer(3,1)
                        .subscribe(integers -> {
                            Log.i(TAG, "accept size: "+integers.size());
                            for (Integer integer : integers) {
                                Log.i(TAG, "accept: "+integer);
                            }
                        });
  • 輸出結(jié)果
2018-12-14 11:24:31.455 29164-29164/com.luwei.lwbaselib I/LwBaseActivity: accept size: 3
2018-12-14 11:24:31.455 29164-29164/com.luwei.lwbaselib I/LwBaseActivity: accept: 1
2018-12-14 11:24:31.455 29164-29164/com.luwei.lwbaselib I/LwBaseActivity: accept: 2
2018-12-14 11:24:31.455 29164-29164/com.luwei.lwbaselib I/LwBaseActivity: accept: 3
2018-12-14 11:24:31.455 29164-29164/com.luwei.lwbaselib I/LwBaseActivity: accept size: 3
2018-12-14 11:24:31.455 29164-29164/com.luwei.lwbaselib I/LwBaseActivity: accept: 2
2018-12-14 11:24:31.455 29164-29164/com.luwei.lwbaselib I/LwBaseActivity: accept: 3
2018-12-14 11:24:31.455 29164-29164/com.luwei.lwbaselib I/LwBaseActivity: accept: 4
2018-12-14 11:24:31.456 29164-29164/com.luwei.lwbaselib I/LwBaseActivity: accept size: 2
2018-12-14 11:24:31.456 29164-29164/com.luwei.lwbaselib I/LwBaseActivity: accept: 3
2018-12-14 11:24:31.456 29164-29164/com.luwei.lwbaselib I/LwBaseActivity: accept: 4
2018-12-14 11:24:31.456 29164-29164/com.luwei.lwbaselib I/LwBaseActivity: accept size: 1
2018-12-14 11:24:31.456 29164-29164/com.luwei.lwbaselib I/LwBaseActivity: accept: 4

concat 操作符

是接收若干個(gè)Observables奄毡,發(fā)射數(shù)據(jù)是有序的,不會(huì)交叉贝或。

Subject

  • 作為 Observable 和 Observer 之間的橋梁
  • 可以當(dāng)做 Observable
  • 可以當(dāng)做 Observer

PublishSubject

繼承至 Subject吼过,它的 Observer 只會(huì)接收到 PublishSubject 被訂閱之后發(fā)送的數(shù)據(jù)。示例代碼如下咪奖;我們只會(huì)接收到 publishSubject3 和 publishSubject4盗忱;

                PublishSubject<String> publishSubject = PublishSubject.create();
                publishSubject.onNext("publishSubject1");
                publishSubject.onNext("publishSubject2");
                publishSubject.subscribe(new Consumer<String>() {
                    @Override
                    public void accept(String s) throws Exception {
                        Log.i(TAG, "accept: "+s);
                    }
                });
                publishSubject.onNext("publishSubject3");
                publishSubject.onNext("publishSubject4");

  • 執(zhí)行結(jié)果
2018-12-14 11:33:18.168 29916-29916/com.luwei.lwbaselib I/LwBaseActivity: accept: publishSubject3
2018-12-14 11:33:18.168 29916-29916/com.luwei.lwbaselib I/LwBaseActivity: accept: publishSubject4

舉一反三

可以看到,在 RxPermissions 這個(gè)獲取權(quán)限的開(kāi)源框架中羊赵,往 Activity 中添加了一個(gè)空的 Fragment趟佃,這個(gè) fragment 才是用來(lái)發(fā)起申請(qǐng)權(quán)限和處理權(quán)限的請(qǐng)求,最后再將結(jié)果返回昧捷,這樣子就避免了我們發(fā)送請(qǐng)求之后揖闸,還需要在 onRequestPermissionsResult 中進(jìn)行處理,并判斷 requestCode 等繁瑣操作料身。想到這里,我們平時(shí)使用 startActivityForResult 時(shí)衩茸,我們也可以同樣采用這樣的思路來(lái)簡(jiǎn)化我們的請(qǐng)求芹血。

同樣的,我們采用添加空白的 fragment,來(lái)做 startActivityForResult 請(qǐng)求幔烛,主要的實(shí)現(xiàn)類有 SimpleForResult 和 SimpleOnResultFragment啃擦,ActivityResultInfo 是請(qǐng)求 model,接下我們先看代碼饿悬。

SimpleForResult


/**
 * @Author: chenjianrun
 * @Time: 2018/12/7
 * @Description:   避免調(diào)用 startActivity 時(shí)令蛉,需要 onActivityResult 處理的類
 */
public class SimpleForResult {
    private static final String TAG = "SimpleForResult";
    private SimpleOnResultFragment mSimpleOnResultFragment;

    public SimpleForResult(AppCompatActivity activity) {
        mSimpleOnResultFragment = getOnResultFragment(activity.getSupportFragmentManager());
    }

    public SimpleForResult(Fragment fragment){
        mSimpleOnResultFragment = getOnResultFragment(fragment.getChildFragmentManager());
    }

    private SimpleOnResultFragment getOnResultFragment(FragmentManager fragmentManager) {
        SimpleOnResultFragment simpleOnResultFragment = findSimpleOnResultFragment(fragmentManager);
        if (simpleOnResultFragment == null) {
            simpleOnResultFragment = new SimpleOnResultFragment();
            fragmentManager
                    .beginTransaction()
                    .add(simpleOnResultFragment, TAG)
                    .commitAllowingStateLoss();
            fragmentManager.executePendingTransactions();
        }
        return simpleOnResultFragment;
    }

    private SimpleOnResultFragment findSimpleOnResultFragment(FragmentManager fragmentManager) {
        return (SimpleOnResultFragment) fragmentManager.findFragmentByTag(TAG);
    }

    public Observable<ActivityResultInfo> startForResult(Intent intent) {
        return mSimpleOnResultFragment.startForResult(intent);
    }

    public Observable<ActivityResultInfo> startForResult(Class<?> clazz) {
        Intent intent = new Intent(mSimpleOnResultFragment.getActivity(), clazz);
        return startForResult(intent);
    }

    public void startForResult(Intent intent, Callback callback) {
        mSimpleOnResultFragment.startForResult(intent, callback);
    }

    public void startForResult(Class<?> clazz, Callback callback) {
        Intent intent = new Intent(mSimpleOnResultFragment.getActivity(), clazz);
        startForResult(intent, callback);
    }

    public interface Callback {
        void onActivityResult(int requestCode, int resultCode, Intent data);
    }
}

SimpleOnResultFragment


/**
 * @Author: chenjianrun
 * @Time: 2018/12/7
 * @Description:    真正調(diào)用 startActivity 和處理 onActivityResult 的類。
 */
public class SimpleOnResultFragment extends Fragment {
    private static Map<Integer, PublishSubject<ActivityResultInfo>> mSubjects = new HashMap<>();
    private static Map<Integer, SimpleForResult.Callback> mCallbacks = new HashMap<>();

    public SimpleOnResultFragment() {
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRetainInstance(true);
    }

    public Observable<ActivityResultInfo> startForResult(final Intent intent) {
        int requestCode = generateRequestCode();
        PublishSubject<ActivityResultInfo> subject = PublishSubject.create();
        mSubjects.put(requestCode, subject);
        startActivityForResult(intent, requestCode);
        return subject;
    }

    public void startForResult(Intent intent, SimpleForResult.Callback callback) {
        int requestCode = generateRequestCode();
        mCallbacks.put(requestCode, callback);
        startActivityForResult(intent, requestCode);
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        //rxjava方式的處理
        PublishSubject<ActivityResultInfo> subject = mSubjects.remove(requestCode);
        if (subject != null) {
            subject.onNext(new ActivityResultInfo(requestCode, resultCode, data));
            subject.onComplete();
        }

        //callback方式的處理
        SimpleForResult.Callback callback = mCallbacks.remove(requestCode);
        if (callback != null) {
            callback.onActivityResult(requestCode, resultCode, data);
        }
    }

    private int generateRequestCode(){
        Random random = new Random();
        for (;;){
            int code = random.nextInt(65536);
            if (!mSubjects.containsKey(code) && !mCallbacks.containsKey(code)){
                return code;
            }
        }
    }
}

ActivityResultInfo

package com.luwei.util.forresult;

import android.content.Intent;

/**
 * @Author: chenjianrun
 * @Time: 2018/12/7
 * @Description:
 */
public class ActivityResultInfo {
    private int requestCode;
    private int resultCode;
    private Intent data;

    public ActivityResultInfo(int requestCode, int resultCode, Intent data) {
        this.requestCode = requestCode;
        this.resultCode = resultCode;
        this.data = data;
    }

    public int getRequestCode() {
        return requestCode;
    }

    public void setRequestCode(int requestCode) {
        this.requestCode = requestCode;
    }

    public ActivityResultInfo(int resultCode, Intent data) {
        this.resultCode = resultCode;
        this.data = data;
    }

    public int getResultCode() {
        return resultCode;
    }

    public void setResultCode(int resultCode) {
        this.resultCode = resultCode;
    }

    public Intent getData() {
        return data;
    }

    public void setData(Intent data) {
        this.data = data;
    }
}

簡(jiǎn)單使用示例

  • 簡(jiǎn)單的 Activity 調(diào)用
// 簡(jiǎn)化調(diào)用 startActivityForResult 及避免在 onActivityResult 中處理繁瑣的結(jié)果
                SimpleForResult simpleForResult = new SimpleForResult(this);
                simpleForResult.startForResult(ToastActivity.class)
                        .subscribe((resultInfo) -> {
                            if (resultInfo.getData() != null) {
                                ToastUtils.showLong(resultInfo.getData().getStringExtra("result"));
                            }
                        });
  • 調(diào)用攝像頭
    /**
     * 打開(kāi)攝像頭
     */
    private void openCamera() {
        try {
            mTmpFile = FileUtils.createTmpFile(this);
        } catch (IOException e) {
            e.printStackTrace();
        }
        simpleForResult.startForResult(getOpenCameraIntent(this, mTmpFile))
                .subscribe((resultInfo -> {
                    if (resultInfo.getResultCode() == RESULT_OK) {
                        mHeadUrl = mTmpFile.getAbsolutePath();
                        ImageLoaderUtils.loadCircleImage(this, ivHeader, mHeadUrl);
                        // 裁剪(如果沒(méi)有要求可裁剪狡恬,也可以不要)
                        startPictureZoom(mTmpFile);
                    }
                }));
    }


    /**
     * 獲取打開(kāi)照相機(jī)的 intent珠叔,適配 Android 7.0
     * @param activity
     * @param mTmpFile
     * @return
     */
    public static Intent getOpenCameraIntent(Activity activity,File mTmpFile){
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        if (intent.resolveActivity(activity.getPackageManager()) != null) {
            if (mTmpFile != null && mTmpFile.exists()) {
                if (Build.VERSION.SDK_INT >= 24) {
                    // 適配 Android 7.0
                    intent.putExtra(MediaStore.EXTRA_OUTPUT,
                            FileProvider.getUriForFile(activity, activity.getPackageName()+".provider",mTmpFile));
                } else {
                    intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(mTmpFile));
                }
            } else {
                Toast.makeText(activity, me.nereo.image_selector.R.string.error_image_not_exist, Toast.LENGTH_SHORT).show();
            }
        } else {
            Toast.makeText(activity, me.nereo.image_selector.R.string.msg_no_camera, Toast.LENGTH_SHORT).show();
        }
        return intent;
    }

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市弟劲,隨后出現(xiàn)的幾起案子祷安,更是在濱河造成了極大的恐慌,老刑警劉巖兔乞,帶你破解...
    沈念sama閱讀 211,817評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件汇鞭,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡庸追,警方通過(guò)查閱死者的電腦和手機(jī)霍骄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)淡溯,“玉大人读整,你說(shuō)我怎么就攤上這事⊙” “怎么了绘沉?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,354評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)豺总。 經(jīng)常有香客問(wèn)我车伞,道長(zhǎng),這世上最難降的妖魔是什么喻喳? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,498評(píng)論 1 284
  • 正文 為了忘掉前任另玖,我火速辦了婚禮,結(jié)果婚禮上表伦,老公的妹妹穿的比我還像新娘谦去。我一直安慰自己,他們只是感情好蹦哼,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布鳄哭。 她就那樣靜靜地躺著,像睡著了一般纲熏。 火紅的嫁衣襯著肌膚如雪妆丘。 梳的紋絲不亂的頭發(fā)上锄俄,一...
    開(kāi)封第一講書(shū)人閱讀 49,829評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音勺拣,去河邊找鬼奶赠。 笑死,一個(gè)胖子當(dāng)著我的面吹牛药有,可吹牛的內(nèi)容都是我干的毅戈。 我是一名探鬼主播,決...
    沈念sama閱讀 38,979評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼愤惰,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼苇经!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起羊苟,我...
    開(kāi)封第一講書(shū)人閱讀 37,722評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤塑陵,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后蜡励,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體令花,經(jīng)...
    沈念sama閱讀 44,189評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評(píng)論 2 327
  • 正文 我和宋清朗相戀三年凉倚,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了兼都。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,654評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡稽寒,死狀恐怖扮碧,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情杏糙,我是刑警寧澤慎王,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站宏侍,受9級(jí)特大地震影響赖淤,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜谅河,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評(píng)論 3 313
  • 文/蒙蒙 一咱旱、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧绷耍,春花似錦吐限、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,762評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至崎苗,卻和暖如春狐粱,著一層夾襖步出監(jiān)牢的瞬間赘阀,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,993評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工脑奠, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人幅慌。 一個(gè)月前我還...
    沈念sama閱讀 46,382評(píng)論 2 360
  • 正文 我出身青樓宋欺,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親胰伍。 傳聞我的和親對(duì)象是個(gè)殘疾皇子齿诞,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容

  • 本篇文章介主要紹RxJava中操作符是以函數(shù)作為基本單位,與響應(yīng)式編程作為結(jié)合使用的骂租,對(duì)什么是操作祷杈、操作符都有哪些...
    嘎啦果安卓獸閱讀 2,851評(píng)論 0 10
  • 項(xiàng)目地址:RxPermissions,本文分析版本: 4c4d4e1 1.簡(jiǎn)介 RxPermissions是基于R...
    SkyKai閱讀 13,218評(píng)論 20 63
  • 記錄RxJava操作符渗饮,方便查詢(2.2.2版本) 英文文檔地址:http://reactivex.io/docu...
    凌云飛魚(yú)閱讀 819評(píng)論 0 0
  • 一但汞、RxJava操作符概述 RxJava中的操作符就是為了提供函數(shù)式的特性,函數(shù)式最大的好處就是使得數(shù)據(jù)處理簡(jiǎn)潔易...
    BrotherChen閱讀 1,601評(píng)論 0 10
  • 你想要什麼,就去努力得到它胡桃。 在工作中練習(xí)和男生接觸踩叭。
    不要做半吊子閱讀 80評(píng)論 0 0