RxJava && Agera Brief analysis of basic call flow from source (2)

Source: Internet
Author: User
Tags switches eventbus

Copyright notice: This article by Jinzhong Hope original article, reproduced please indicate the source:
Article original link: https://www.qcloud.com/community/article/124

Source: Tengyun https://www.qcloud.com/community

Rxjava && Agera from the source to briefly analyze the basic call flow (1) We analyze the "1. Subscription process", "2. Transformation Process", the next article we continue to analyze the "3. Thread switching Process"

3. Thread switching process

From the above we know that Rxjava can help us to transform the data flow flexibly, in order to achieve the purpose of chain structure operation, but it is more powerful than this. Let's take a look at one of its other tools, scheduler Scheduler : As we know, Scheduler is to Observable add multithreading capabilities to the data stream prepared, generally we will use subscribeOn() , methods to pass through observeOn() the Scheduler corresponding To specify how each part of the data flow should run on which thread. For us, the most common scenario is to update the UI on the main thread after the non-main thread gets and processes the data:

This is our very common invocation method, one go the processing between the different threads is done, because it is chained so the structure is very clear, we now look at the thread switching process.

  • subscribeOn()

    When we callsubscribeOn()The time:

    As you can see, this is also calledcreate()To generate aObservable, whileOperatorSubscribeOnis the realization of theOnSubscribeinterface, while the originalObservableAnd what we need.schedulerIncoming:


    As you can see, here's thesubscriberThe processing and the previous articleOperatorMapIncall()RightsubscriberVery similar to the processing. Here we will also be based on the incomingsubscriberTo construct a newSubscribers, but most of this process is done by the workerschedule()To carry out, from the backsetProducer()The judgment of the thread, and then the combinationsubscribeOn()The purpose of the method we can presumably infer that this worker is, to a certain extent, equivalent to a new thread of agent performer,schedule()The implementation should be very similar to run () in the thread class. Let's take a look at the worker's execution process.
    First fromSchedulers.io()Enter:

    This is the process of getting scheduler through hooks, we don't care, we go straight in.CachedThreadScheduler, look at it.createWorker()Method:

    The pool here is an atomic variable referenceAtomicReference, and the ones held areCachedWorkerPool, so the pool is the name of the pool where the worker is stored, and we get the required worker from the cache pool and encapsulate it as aEventLoopWorker

    Here we finally found the targetThreadWorker, it inherits fromNewThreadWorker, the previous schedule () method will eventually come to thisscheduleActual()Fangfali:

    Here we see the executor thread pool, which we useSchedulers.io()The essence of the eventual thread switching is here. Now let's start by combing the previous process:

    InsubscribeOn(), we will be reborn into aObservable, it's membersonSubscribewill be in the targetSubscriberWhen subscribing, use the incomingSchedulerWorker as the thread dispatch performer, notifying the original in the corresponding threadObservableSend a message to the temporary generated in this procedureSubscriberThis oneSubscriberThe target subscriber will be notified, and this will be done.subscribeOn()The process.

  • observeOn()

    Let's take a look at the following observeOn() :

    We look directly at the final part of the call, and we can see that there is another one here, which lift() comes in here OperatorObserveOn , and it OperatorSubscribeOn 's different, it's a Operator function that Operator we've talked about before, and it constructs a new observer ObserveOnSubscriber and implements Action0 Interface:

    As can be seen here, ObserveOnSubscriber all the messages sent to the target are Subscriber child switched to recursiveScheduler the thread for processing, and the purpose of Cheng Che the line back is reached.

Summarize the observeOn() overall process as follows:

Contrast subscribeOn() and observeOn() These two processes, it is not difficult to find the difference: The subscribeOn() initial Observable subscription event is switched to the whole of another thread, but the observeOn() initial Observable The sent message switches to another thread to notify the target subscriber. The former switches "subscribe + send" to a thread, which switches "send" to a thread. So, the functionality implemented in our code is actually:

This makes it easy to implement these common scenarios such as time-consuming tasks in sub-threading operations, and updating operations on the main thread.

4. Other roles

Subject
Subject in the RX series is a special role, it inherits the observable and also implements the observer interface, that is, it can be as an observer, but also as the observer, he is generally used as a link to a number of different observable, The bond between the observer. You might wonder if we've got a observable, like map() this, to flatMap() change the flow of data, why introduce subject? This is because subject's work is not a conversion connection to the content of the observable data stream, but rather the dispatch of the data flow itself between observable and observer. The light may still be vague, so let's cite an example from the RxJava Essentials:

We create() created a publishsubject, the Observer successfully subscribed to the subject, but the subject has no data to send, and we just know that he will send a string value in the future. After that, when we call subject.onNext() , the message is sent, the observer onNext() is triggered, and the "Hello World" is output.

Here we notice that when the subscription event occurs, our subject is not generating the data stream until it launches "Hello world" and the data flow starts to run, just imagine if we change the subscription process and subject.onNext() position, then observer will not accept " Hello World "(this is not nonsense--| | | ), so this also fundamentally reflects the hot and cold differences of observable.

In general, our observable are cold observables, like watching video, we have to start from scratch every time we open a new video, while Subject the default is hot observables, like watching live, video data is always new.
Based on this attribute, nature has the Subject ability to select and dispatch incoming data streams, so our use of them is Subject often based on the following ideas:

In the previous example, we used publishsubject, which only emitted data from the original observable after the point at which the subscription occurred, to the observer. Wait a minute, does this feature sound familiar?

Yes, that's Eventbus and Otto. (Rxjava's appearance slowly let Otto out of the stage, now Otto's repo is already deprecated state, and Eventbus still strong) based on Rxjava observation subscription cancellation ability and Publishsubject function, It is very easy to write a simple event bus framework that implements the most basic functions:

Of course, there are other subject, such as,, and other BehaviorSubject ReplaySubject AsyncSubject types, we can go to the official documents, written in very detailed, here is not introduced.

Three. PostScript

I believe that in the recent period, mention Rxjava, we will think of Google recently just open source Agera. Agera is a reactive programming frame specifically built for Android, and will inevitably be compared to Rxjava. The main process analysis of Rxjava in front of this article is near the end, now we look at Agera this thing is how the matter.

First come to the conclusion:

Agera originally developed an internal framework for Google Play movies, which is now open source, although it is only after Rxjava, but completely independent of Rxjava, and it has nothing to do with it (just open source time is very subtle 233333). Compared with Rxjava, Agera is more focused on the Android life cycle, while Rxjava is more purely terrestrial to the Java platform than to Android.

Perhaps you might ask, "What about rxandroid? "In fact, rxandroid in the 1.0 version of the very large refactoring, many modules were split into other projects, but also deleted some of the code, the only part of the memory is related to the Android thread, such as AndroidSchedulers , and MainThreadSubscription so on. In view of this situation, we will not pay attention to the rxandroid, first of all focus on the Agera.

Also based on the observer pattern, Agera and Rxjava are broadly similar in character categories, with two of the main characters in Agera: Observable (Observer), Updatable (Observer).



Yes, compared to Rxjava Observable , Agera is Observable just a simple interface, there is no fan of the existence, updatable is also so, so how do we do the message delivery? This requires a different interface:

Finally, we see the generic T, and our message's ability to deliver is dependent on this interface. So we'll combine this interface with the basics Observable :

This is, to a Repository<T> certain extent, the Rxjava we want Observable<T> . Similarly, repository also has two types of implementations:

    • Direct-the data contained is always available or can be computed synchronously; a direct repository is always active (active)

    • Deferred-The data contained is asynchronous computation or pull-out; a deffered repository is inactive (inactive) until updatable is added
      Does it feel familiar? Yes, repository also has a hot and cold distinction, but we are not going to pay attention to this now. Go back up and look, now that the role of the data is being sent, how do we receive the data? The answer is Receiver :

Believe to see here, we should also vaguely feel: in the world of Agera, the transmission of data and events are separated from each other, which is the most essential difference between the Agera and the RX series at present. The Agera uses a push event, pull data model, which means that the event does not carry any data, and Updatable when it needs to be updated, it itself assumes the task of pulling data from the data source. In this way, the responsibility for providing the data is Observable split from the middle Repository , giving it the ability to focus on sending simple events such as button clicks, a pull-down refresh trigger, and so on.

So what are the benefits of such an implementation?

When these two processing distribution logic leaves, Updatable you do not have to observe the Repository history of the complete data changes from, after all, in most scenarios, especially in the context of updating the UI, the latest data is often the useful data.

But I just need to see the historical data of change, what should I do?

Do not worry, here we have another role Reservoir :

As the name implies, Reservoir we are used to store changes in the data in the place, it inherits, it is Receiver Repository equivalent to the same time to receive data, the ability to send data. By looking at its implementation, we can know that its essential operations are implemented using the internal queue: after receiving the data via accept (), into row, and get() then dequeue by getting the data. If one Updatable observes this, the next data that is to be queued Reservoir after a dispatch change in its queue is available (not empty), the updatable is notified, and the data is further pulled to send Receiver .

Now that we have a rough idea of the functional properties of these characters, let's take a look at the official sample code:


Is it some foggy feeling? Thanks to the comments, we can probably guess what's going on: Use the required picture specifications as parameters to stitch into the URL, pull the corresponding picture and display it imageview. Let's combine the API to see the whole process:

  • Repositories.repositorywithinitialvalue (Result.absent ())
    Create a repository that can be run (or executed).
    The initialization of the incoming value is result, which is used to summarize some of the apply() merge() immutable objects such as the result of an operation, and there are two states succeeded() failed() .
    Back to Reventsource

  • Observe ()
    Used to add a new observable as an event source for updating our pictures, which is not required in this example.
    ReturnRFrequency

  • Onupdatesperloop ()
    In each Looper Thread loop, if you have update () processing from multiple event source, you only need to open a data processing stream.
    Back to Rflow

  • Getfrom (New Supplier (...))
    ignores the input value and uses the newly acquired data from the given supplier as the output value.
    Back to Rflow

  • GoTo (Executor)
    Switches to the given executor to continue the data processing stream.

  • Attempttransform (function ())
    Uses the given function () transformation input value, if the transformation fails, the data flow is terminated, and if successful, the new transformed value is taken as the output of the current flow instruction.
    Back to Rtermination

  • Orskip ()
    If the previous operation checks for failure, the remaining data processing stream is skipped, and all added updatable are not notified.

  • Thentransform (function ())
    Similar to Attempttransform (function ()), the difference is that notifications are given when necessary.
    Back to Rconfig

  • Ondeactivation (Send_interrupt)
    Used to clarify the behavior of repository when it is no longer active.
    Back to Rconfig

  • Compile ()
    Perform this repository.
    Back to Repository

The whole process seems to be nothing special at first, but the real mystery is actually hidden in the return value of each step:
The initial REventSource<T, T> represents the beginning of the event source, which is received from the incoming value T initialValue , where the first T is the type of the current repository data, and the second T is the type of data at the beginning of the data processing stream.

After that, when observe () is called, we pass in the event source REventSource , which is equivalent to setting the desired event source and the corresponding start, which returns the RFrequency<T, T> property that it inherits from REventSource , adding the frequency of the event source to it.

After that, we came onUpdatesPerLoop() to the point where the number of data streams opened (that is, the frequency above) was returned to Rflow, which means that our data flow is officially generated. At the same time, this is also the starting point for streaming calls.

After we get our rflow, we can provide it with a data source, which is what we said earlier, so that Supplier getFrom() our data flow has the real meaning of the data "dry".

With the data we can transform the data as needed, and we can use it directly to transform() return Rflow for further streaming calls, or call Attempttransform () to handle possible exceptions such as Orskip (), Orend () to continue the streaming call.

After a series of streaming calls, we are finally done with the data processing, and now we can choose to make a final package of the molded information, thenTransform() or merge with another supplier thenMergeIn() . After these processing, our return value is converted to Rconfig, entering the state of the final configuration and the end of the repository declaration.
In the final configuration process, we call onDeactivation() , for this repository explicit behavior when the end enters inactive state, we can enter the final method if we don't need other redundant configuration compile() . When we call compile() , we will execute and generate this repository in accordance with all the processes and configurations that we have traversed earlier. By this, our repository was truly created.

The above is the whole process of repository from scratch. When Repository is born, we can transfer the data we need. Then go back to the example code above:

We have onResume() onPause() added, removed, and updatable each of these two life cycles. The Agera is clearly clearer and neater than Rxjava's approach to unsubscribe through subscription. Our activity implements the updatable and receiver interfaces, looking directly at its implementation:

You can see that the data is sent to, that is, repository receiver in the corresponding accept () method to receive the bitmap we want, this picture is displayed, the sample code in the complete process is finished.

Summarize the above process:

  • The Repositories.repositoryWithInitialValue() origin Reventsource is generated first.

  • After configuring observable, enter the Rfrequency state, and then configure the stream count for the data stream.

  • After the previous configuration is completed, the data stream Rflow generated, and then through getFrom() , mergeIn() , transform () and other methods can be further streaming calls, you can also use attemptXXX() the method instead of the original method, followed by the call orSkip() , orEnd() error handling processing. When the attemptXXX() method is used, the data flow state becomes rtermination, which represents the ability of the state to end the data flow at this time, whether the end stream is to be triggered based on the failed check, and, in combination with subsequent calls, orSkip() orEnd() our data flow will be RTerminationswitch again to to RFlow make the subsequent streaming call.

  • After a series of streaming, we need to end the data flow, we can choose to call the thenXXX() method, the final processing of the data flow, after processing, the data flow status will be changed to Rconfig, the behavior can also add error handling processing, select thenAttemptXXX() method, The following is also connected orSkip() , and orEnd() the final data stream will be converted to the Rconfig state.

  • At this point, we can select the final configuration of the data flow before the end, such as whether the call to onDeactivation() configure the process from "subscribe" to "unsubscribe" requires continued data flow, and so on.

  • After everything was deployed, we had the compile() Rconfig to get the final molded repository, which had the ability to add updatable, send data to notify receiver.

  • We add as needed Updatable , and repository send an event notification when the data flow processing is complete update() Updatable .

  • updatable receives the notification, it pulls repository's results data and sends the data via accept () to receiver. Complete the process of Push event, pull data.

The above is the internal basic flow of a agera streaming call. You can see that, in addition to the Push event, pull data this feature, Golazy loading mode (not described in this article), and so on, relying on a more streamlined approach, agera the flow of the call process is also able to achieve a clear process, and the difficulty of getting started compared to Rxjava is also a bit simpler, Open source author is Google's team also let some g powder on its popularity increased a lot. But Agera in this writing is AGERA-1.0.0-RC2, the future version there are many uncertainties, in contrast to the RX series developed so long, the framework is relatively mature. Whether to use Agera or Rxjava, we choose according to their preferences.

The new debut, the article will inevitably have the wrong omission and the expression is not clear, I hope that we have a lot of criticism, thank you!

Reference & Outreach:
RxJava Wiki
Agera Wiki
RxJava for Android Developers
Google Agera vs. Reactivex
When Iron Mans becomes reactive
Top 7 Tips for RxJava on Android
How to Keep your RxJava subscribers from leaking
Rxjava–the production line

Article source public number: QQ Space terminal Development team (QZONEMOBILEDEV)

RxJava && Agera Brief analysis of basic call flow from source (2)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.