Learning opportunity

I have been in touch with RxJava for some time, but I always feel that I am still in the beginning stage of using and understanding RxJava. On the one hand, it has something to do with the fact that you didn’t go deep enough to learn RxJava, because you used some basic operators, and you can boast that you know RxJava. On the other hand, RxJava event-driven programming ideas, the author has always understood the bad.

I don’t think it makes much sense to just learn operators. In fact, I’ve spent a lot of time learning operators before, only to find that it’s not working because I still don’t know when to use the RxJava operator properly. I asked my friend, he said you can try to read the source code of some Rx open source projects, from simple start, to learn the convenience Rx brings, and the change of way of thinking.

This same friend again recommended RxActivityResult to me. Code is not much, very suitable for me to learn. So let’s go to startActiviityForResult() the other way around.

Introduction to the

RxActivityResult is another Rx open source masterpiece from VictorAlbertos. The library was recently updated to fully support AndroidX. When you’ve had enough of onActivityResult() accepting data from a system (such as a camera) or your own callback, try this library and say goodbye to onActivityResult(). A brief description of the library’s features:

  • The incomingActivityFragmentCan be opened in any classIntent.
  • The data is encapsulated in an observableObservableIn return, means can continue to enjoyRxJavaOperator convenience.

use

  1. First under Projectbuild.gradleaddmavenRely on.
allprojects {
    repositories {
        google()
        jcenter()
        maven { url "https://jitpack.io"}}}Copy the code
  1. Under the background of the appbuild.gradleaddRxActivityResultRxJavaRely on.
implementation 'com. Making. VictorAlbertos: RxActivityResult: 0.5.0-2 x'
implementation 'the IO. Reactivex. Rxjava2: rxjava: 2.2.3'
Copy the code
  1. After adding the dependency, we need to set theApplicationRegistered inRxActivityResult
class MyApp : Application() {

    override fun onCreate(a) {
        super.onCreate()
        RxActivityResult.register(this)}}Copy the code
  1. inMainActivityClick the button to jump toMain2Activity. Here is a code example
@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)
                    }
            }
    }
Copy the code
  1. inMain2ActivityClick the button to send back data.
override fun onCreate(savedInstanceState: Bundle?). {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main2)
        btnResult.setOnClickListener {
            val intent = intent
            intent.putExtra("resultData"."I'm the data back.")
            setResult(Activity.RESULT_OK, intent)
            finish()
        }
    }
Copy the code

Ok, that’s it for a simple use. If used with RxBinding, you can make your code more Rx and ensure the integrity of the flow of action events.

 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)
            }
Copy the code

With a few lines of code, you say goodbye to onActivityResult() and can receive the returned data. Here are two questions:

  • inApplicationWhy register in.
  • onActivityResult()Who is the concrete implementation of.

Source code analysis

  1. So let’s take a look firstApplicationRegister in.
class MyApp:Application() {

    override fun onCreate(a) {
        super.onCreate()
        RxActivityResult.register(this)}}Copy the code

To briefly introduce ActivityLifecycleCallbacks, it is defined in the Application an interface that can be used to monitor all of the Activity lifecycle callback, the callback and prior to the Activity life cycle. Using ActivityLifecycleCallbacks can also judge the current App in the foreground or the background. Please refer to the specific usage by yourself.

RxActivityResult. The register () is actually returned to the library writers define ActivitiesLifecycleCallbacks class. By looking at the source code, we know that the Application object passed in is used to register the listening Activity lifecycle.

Now that you’ve answered the first question, register RxActivityResult in your Application so that you can listen to the life cycle of all activities. After all, it makes no sense to go to startIntent() after onPause.

  1. Then look at theActivitySpecific use of
  RxActivityResult
                    .on(this) / / step 1
                    .startIntent(intent) / / step 2
                    .map { it.data }
                    .subscribe {
                        val extra = it.getStringExtra("resultData")
                        println(extra)
                    }
Copy the code
  • callon()The incomingthisObject to determine whether a user is fromActivityorFragmentThe operation of the
  • startIntent()Method will eventually be calledstartHolderActivity().
  @SuppressLint("CheckResult")
        private Observable<Result<T>> startHolderActivity(Request request, @Nullable OnPreResult onPreResult) {

            OnResult onResult = uiTargetActivity ? onResultActivity() : onResultFragment(); // Determine the Intent launched from an Activity or Fragment
            request.setOnResult(onResult);
            request.setOnPreResult(onPreResult);
        
            // Set the request object
            HolderActivity.setRequest(request);

            // From the current Activity, start 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)); }});/ / return PublishSubject
            return subject;
        }
Copy the code

Look at the first onResultActivity ()

private OnResult onResultActivity(a) {
            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();
                  // Launch Result
                    subject.onNext(new Result<>(activity, requestCode, resultCode, data));
                    subject.onComplete();
                }

                @Override
                public void error(Throwable throwable) { subject.onError(throwable); }}; }Copy the code

Create an OnResult object and emit the Result Result in Response ().

  • Subject SubjectIt can be a data sourceObservableCan also be a subscriber to the dataObserver.
public abstract class Subject<T> extends Observable<T> implements Observer<T> {... }Copy the code

As you can see from the source code, the Subject is actually an Observable, but it implements the Observer interface and can emit and terminate transmitting data through onNext, onComplete, and onError methods. The author uses a PublischSubject to publish Result. The PublischSubject only accepts data published after being subscribed.

  1. Look at theHolderActivityThe operation
  • Open the actual Intent object in onCreate()

  • Close HolderActivity in onActivityResult and send back data in onDestroy

 @Override
    protected void onDestroy(a) {
        super.onDestroy();
        if(onResult ! =null)
            onResult.response(requestCode, resultCode, data);
    }
Copy the code

To summarize the general logic, for example, in our shopping process, we place an order for books from JINGdong, and the shopkeeper asks his employee, Xiao Wang, to search for books in the warehouse. And package and send express (publischsubjection.onnext (Result())). A Courier delivers the book to the customer’s door, and the customer checks the purchase information (intent.getStringExtra(“resultData”)) to get the book if the information is correct.

Summary and Reflection

Through analyzing RxActivityResult library of simple, understand the ActivityLifecycleCallbacks and PublischSubject in concrete using three sides in the library. You also learned about some RxJava operators, such as the takeWhile filter operator. More importantly, I usually get data from onActivityResult() without encountering RxActivityResult (), which breaks my previous understanding that it is possible to process onActivityResult() data in this way.

When I am pleased with the results of the current learning method (use – source analysis – summary). My friend’s words alerted me. Reading the source code is just the first step. More importantly, the master of the idea, standing in a higher Angle to think, why the design. You should not just be satisfied with the basic source code analysis, but the design behind it is the essence.

If only to the source analysis, according to the author’s ideas to clear away the clouds, the progress is limited. I need to think further, which is what I need to learn next.