RxActivityResult 突破固有思惟,獲取 onActivityResult 數據

學習契機

接觸 RxJava 有一段時間了,但總感受對於 RxJava 的使用和理解還在入門階段。一方面和本身沒有去深刻學習有關,覺得使用了一些基礎的操做符,就敢吹牛說本身掌握 RxJava。另外一方面對RxJava 事件驅動型 的編程思想,筆者始終領悟的很差。java

我認爲單純的學習操做符,實際意義不大。事實上,筆者以前也花費了大量的時間學習操做符,到頭來發現效果不佳,由於我仍是不知道什麼時候,該正確的去使用 RxJava 操做符。我便向朋友請教,他說你能夠試着去閱讀一些 Rx 開源項目的源碼,從簡單的入手,去學習 Rx 帶來的便利,和思惟方式的改變。react

又是這位朋友,向我推薦了 RxActivityResult。代碼量很少,很適合我學習。下面,讓咱們換種方式,去 startActiviityForResult()git

簡介

RxActivityResultVictorAlbertos 大神的又一個 Rx 開源力做,該庫不久前的更新,現已全面支持 AndroidX。當你已經受夠了,從 onActivityResult() 中接受來自系統(如相機),或者本身的回調數據,不妨嘗試下這個庫,讓你今後告別 onActivityResult()。簡單介紹下這個庫的特色:github

  • 傳入 ActivityFragment 的有效實例,就能夠在任何類開啓一個 Intent
  • 數據被封裝在一個可觀察的 Observable 中返回,意味着能夠繼續享受RxJava 操做符的便利。

使用

  1. 首先在 Project 下的 build.gradle 添加 maven 依賴。
allprojects {
    repositories {
        google()
        jcenter()
        maven { url "https://jitpack.io" }
    }
}
複製代碼
  1. 在 app 下的 build.gradle 添加 RxActivityResultRxJava 的依賴。
implementation 'com.github.VictorAlbertos:RxActivityResult:0.5.0-2.x'
implementation 'io.reactivex.rxjava2:rxjava:2.2.3'
複製代碼
  1. 添加完依賴,咱們須要在 Application 中註冊 RxActivityResult
class MyApp : Application() {

    override fun onCreate() {
        super.onCreate()
        RxActivityResult.register(this)
    }
}
複製代碼
  1. MainActivity 中經過點擊按鈕,跳轉至 Main2Activity。如下是代碼示例
@SuppressLint("CheckResult")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val intent = Intent(this, Main2Activity::class.java)
        btnJump
            .setOnClickListener {
                RxActivityResult
                    .on(this)
                    .startIntent(intent)
                    .map {
                        it.data()
                    }
                    .subscribe {
                        val extra = it.getStringExtra("resultData")
                        println(extra)
                    }
            }
    }
複製代碼
  1. Main2Activity 中,點擊按鈕回傳數據。
override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main2)
        btnResult.setOnClickListener {
            val intent = intent
            intent.putExtra("resultData", "我是回傳的數據")
            setResult(Activity.RESULT_OK, intent)
            finish()
        }
    }
複製代碼

ok,到此一個簡單的使用就完成了。若是搭配 RxBinding 使用,可以讓本身的代碼更加 Rx,保證這一系列操做事件流的完整性。編程

btnJump
            .clicks()
            .throttleFirst(500, TimeUnit.MILLISECONDS)
            .map { Intent(this, Main2Activity::class.java) }
            .flatMap {
                RxActivityResult.on(this)
                    .startIntent(it)
            }
            .map{ it.data() }
            .subscribe {
                val stringExtra = it.getStringExtra("resultData")
                println(stringExtra)
            }
複製代碼

經過寥寥的幾行代碼,便告別了 onActivityResult(),而且能夠接收到返回的數據。這裏先拋出兩個問題:app

  • Application 中爲啥要註冊。
  • onActivityResult() 的具體實現是誰。

源碼分析

  1. 首先咱們看下 Application 中的註冊。
class MyApp:Application() {

    override fun onCreate() {
        super.onCreate()
        RxActivityResult.register(this)
    }
}
複製代碼

先簡單介紹下 ActivityLifecycleCallbacks,它是定義在 Application 中的一個接口,能夠用來監聽全部 Activity 生命週期的回調,而且優先於 Activity 生命週期的回調。使用 ActivityLifecycleCallbacks 也能夠判斷當前 App 處於前臺仍是後臺。具體的使用請自行查閱。maven

RxActivityResult.register() 其實返回的是庫做者定義的 ActivitiesLifecycleCallbacks 類。經過查看源碼得知,使用了傳入的 Application 對象去註冊監聽 Activity 的生命週期。ide

到如今也就能夠回答提出的第一個問題,在 Application 中註冊 RxActivityResult,是爲了能夠監聽到全部 Activity 的生命週期。畢竟在 onPause 以後去 startIntent() ,是沒有意義的。源碼分析

  1. 接着看下 Activity 中的具體使用
RxActivityResult
                    .on(this) // 步驟 1
                    .startIntent(intent) // 步驟 2
                    .map { it.data }
                    .subscribe {
                        val extra = it.getStringExtra("resultData")
                        println(extra)
                    }
複製代碼
  • 調用 on() 傳入的 this 對象,用於判斷用戶是從 Activity 或者 Fragment 的操做
  • startIntent() 方法,最終會調用 startHolderActivity()
@SuppressLint("CheckResult")
        private Observable<Result<T>> startHolderActivity(Request request, @Nullable OnPreResult onPreResult) {

            OnResult onResult = uiTargetActivity ? onResultActivity() : onResultFragment(); // 判斷從 Activity 或者 Fragment 啓動的 Intent
            request.setOnResult(onResult);
            request.setOnPreResult(onPreResult);
        
            // 設置請求對象
            HolderActivity.setRequest(request);

            // 從當前 Activity ,打開 HolderActivity 
            activitiesLifecycle.getOLiveActivity().subscribe(new Consumer<Activity>() {
                @Override
                public void accept(Activity activity) throws Exception {
                    activity.startActivity(new Intent(activity, HolderActivity.class)
                            .addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION));
                }
            });
          
            // 返回 PublishSubject
            return subject;
        }
複製代碼

先看下 onResultActivity()學習

private OnResult onResultActivity() {
            return new OnResult() {
                @Override
                public void response(int requestCode, int resultCode, Intent data) {
                    if (activitiesLifecycle.getLiveActivity() == null) return;

                    //If true it means some other activity has been stacked as a secondary process.
                    //Wait until the current activity be the target activity
                    if (activitiesLifecycle.getLiveActivity().getClass() != clazz) {
                        return;
                    }

                    T activity = (T) activitiesLifecycle.getLiveActivity();
                  // 發射 Result 結果
                    subject.onNext(new Result<>(activity, requestCode, resultCode, data));
                    subject.onComplete();
                }

                @Override
                public void error(Throwable throwable) {
                    subject.onError(throwable);
                }
            };
        }
複製代碼

建立一個 OnResult 對象,而且在 response() 中發射 Result 結果。

  • Subject Subject 既能夠是數據源 Observable,也能夠是數據的訂閱者 Observer
public abstract class Subject<T> extends Observable<T> implements Observer<T> {
    ...
}
複製代碼

經過查看源碼能夠看到,Subject 實際上仍是 Observable,只不過它實現了 Observer接口,能夠經過 onNextonCompleteonError 方法發射和終止發射數據。做者在發射 Result 的時候,使用了 PublischSubjectPublischSubject 的特色是: Observer 只接受被訂閱以後發射的數據。

  1. 看下 HolderActivity 中的操做
  • onCreate() 中打開真正的 Intent對象

  • onActivityResult 中關閉 HolderActivity,而且在 onDestroy 回傳數據

@Override
    protected void onDestroy() {
        super.onDestroy();
        if (onResult != null)
            onResult.response(requestCode, resultCode, data);
    }
複製代碼

總結下大致的邏輯,比如咱們購物的流程,從京東下單買書 (startActivityForResult),店主交待員工小王(HoldrActivity)去倉庫查找書籍,並打包發送快遞(PublischSubject.onNext(Result()))。快遞員送貨上門,顧客覈對購買的信息(intent.getStringExtra("resultData")),信息無誤的話獲取購買的書籍。

總結與思考

經過對 RxActivityResult 庫的簡單分析,瞭解了 ActivityLifecycleCallbacksPublischSubject 在三方庫中的具體使用。也認識了一些 RxJava 的操做符,如 takeWhile 過濾操做符。更重要的是,在沒有碰見 RxActivityResult 時,筆者一般都是循序漸進的在 onActivityResult() 中獲取數據,而做者的這種方式,打破了我以前的認識,原來還能夠這樣處理 onActivityResult() 數據。

當我對目前這種學習方式(使用-源碼分析-總結),所帶來的收穫沾沾自喜的時候。朋友的一番話,又警醒了我。閱讀源碼,只是進階的第一步。更重要的是,對思想的掌握,站在更高的角度去思考,爲何這樣設計。而不該該只知足於基礎的源碼分析,背後的設計思想纔是精髓。

若是隻是對源碼進行分析,按照做者的思路去撥開雲霧,獲得的進步是有限的。須要再進一步的 思考,這將是我接下來須要學習的地方。

相關文章
相關標籤/搜索