Recently, I used The RxBinding from The Head of JakeWharton in my project. In a form validation module, I found that using RxBinding can achieve a good effect, which reduces the amount of code and makes the logic clearer. Marveling at its magic, I looked at the source code and found that it was not very complicated, so I decided to follow the source code to create a simple version of RxBinding, to deepen my understanding of RxJava.

Two objectives are expected to be achieved:

  • willViewtheClick on the eventIn order toRxJavaimplemented
  • willTextViewAs well asA subclassOf theThe text changesIn order toRxJavaimplementation

Achieve goal one first. Set up a listener for the view that sends events downstream each time a click event arrives.

Let’s take a look at how the original RxBinding implements click event subscriptions.

RxView.clicks(tv_xx).subscribe({ .... dosomething() })Copy the code

Clicks (View View) ¶ RxView.clicks(View View) returns an Observable that can be subscribed to. The rxView. clicks(View View) returns a reference to the View that needs to be subscribed to.

The original RxBinding returns an Observable that can be subscribed via a static method. Let’s just do the same. In the spirit of learning, we don’t have to worry about these things.

Observable observable observable observable observable observable observable observable observable observable observable observable observable observable observable observable observable observable observable observable observable observable observable observable observable observable observable observable observable observable observablereturn
     */
    public static Observable clicks(View view) {
        returnnull; }}Copy the code

The code is simple: a static method returns an Observable. Since we haven’t written the corresponding Observable, we’ll return null for now.

First of all, our Observable must have a close relationship with view, so it must have a reference to view. So let’s write it like this: Create a New Observable called ViewClickObservable that inherits from the Observable and passes the view into the construct and saves it.

public class ViewClickObservale extends Observable { private View mView; public ViewClickObservale(View mView) { this.mView = mView; } / / Override protected void subscribeActual(observer observer) {}Copy the code

We see that the code has a subscribeActual(Observer Observer) method that has to be overwritten as an abstract method in the Observable class that is called when the Observable is subscribed downstream. The observer that the parameter is passed in is our emitter. Some people may have a question here, the observer is not an observer, how to become a transmitter, the launch event is not the observer to do? It’s a bit of a roundabout way to get here if you think in the same way. But if you dig into RxJava, you’ll see that it’s nothing more than a responsive style with various wrappings of Java syntax, chain calls. For example, if you normally receive an event in an Observer’s onNext() method using RxJava, the model you have in mind must be that an event is sent upstream to the Observer downstream, and the Observer receives the event in onNext(), but essentially calls the upstream obser internally Ver’s onNext() method is used to describe the upstream observer because operators may be used in the middle, and the function of these operators is to wrap and transform the downstream observer layer by layer, or restrict it, and eventually pass it to the Observable at the source, and then use the wrapped transform The Observer emits events, and because each operator has a different wrapper modification effect, it can receive different effects downstream.

Now that we have a general idea of how this works, we can continue to modify our ViewClickObservale class. We know that the incoming observer is an emitter, so where does the event come from? It’s definitely still a click event. Every time we get a click event, we’re just going to send an event downstream and keep adding code.

public class ViewClickObservale extends Observable<Object> { private View mView; public ViewClickObservale(View mView) { this.mView = mView; Override protected void subscribeActual(final observer observer) {/ / Override protected void subscribeActual(final observer observer) { Mview. setOnClickListener(new View);OnClickListener() {
            @Override
            public void onClick(View v) {
                observer.onNext("onClick"); }}); }}Copy the code

This is a potential security issue where the compiler indicates that a generic type is not specified for the Observer. The first time I saw this hint I thought, since it is a click event, the downstream doesn’t care about the event itself, just send “onClick”(String). Since String is a subclass of Object, the generic type specifies this:

Protected void subscribeActual(final Observer<? extend Object> observer)Copy the code

The Observer forces the generic type to be
type, and then I’ll change it to this and it’s fine.

protected void subscribeActual(final Observer<? super Object> observer)
Copy the code

I feel strange, I want to send the event is a String, which is a subclass of Object, should use
, whereas
is correct. After thinking for a long time, I finally understood:

  • use<? extend Object>The representation type isObjectAnd subclasses, representing an unknown type, maybeInt, also can beStringThe compiler does not know the type you specified, so it will not allow you to send itStringBecause you can specify it as Int or whatever.
  • use<? super Object>Indicates that the specific type can only beObjectAnd the parent class, causeFor the ObjectThere are no superclasses, which means onlyIs the Object.StrinG andIntAre allObjectSubclass, so sendStringorIntIt’s all fine,ObjectType references can refer to them.

Once you’re done, modify the code for the RxView class

Public class RxView {/** * returns a subscriptable Observable ** @param view ** @param view * @return
     */
    public static Observable<Object> clicks(View view) {
        returnnew ViewClickObservale(view); }}Copy the code

Instead of returning null, return the Observable we just wrote and test it.

The code in MainActivity:

public class MainActivity extends AppCompatActivity {

    String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        RxView.clicks(findViewById(R.id.tv_obs))
                .subscribe(new Consumer<Object>() {
                    @Override
                    public void accept(Object o) throws Exception {
                        Log.d(TAG, "I got clicked."); }}); }}Copy the code

There was only one TextView in the layout. I clicked it three times and it printed the following log:

05-03 23:55:42. 143/1770-1770, April. Lesincs. Rxbinding_demo D/MainActivity: I was hit the 05-03 23:55:43. 068, 1770-1770 / April. Lesincs. Rxbinding_demo D/MainActivity: I was hit the 05-03 23:55:43. 780, 1770-1770 / April. Lesincs. Rxbinding_demo D/MainActivity: I was clickedCopy the code

Test successful! A simple version of RxBinding has been developed. There is not much code, but you need to understand RxJava to understand why it is written. The original version also has the ability to unsubscribe and check the main thread, which is very strict.

The second goal is to implement text changes in TextView and subclasses in RxJava. Stay tuned.