Android RxBinding

In the previous tutorials, we discussed RxJava and some of its operators. Today we will discuss the RxBinding library in our Android Application.

在之前的教程中,我们讨论了RxJava及其一些运算符 。 今天,我们将在Android应用程序中讨论RxBinding库。

Rx绑定 (RxBinding)

We know that RxJava is a reactive event-based programming paradigm.
RxBinding is a set of support libraries to make the implementation of user interaction with the UI elements in Android easier.

我们知道RxJava是一种基于事件的React式编程范例。
RxBinding是一组支持库,可简化与Android中的UI元素的用户交互的实现。

To use RxBinding in your application you must include:

要在您的应用程序中使用RxBinding,您必须包括:

implementation  'com.jakewharton.rxbinding2:rxbinding:2.0.0'

Using this along with the RxJava dependency:

与RxJava依赖项一起使用:

implementation  'io.reactivex.rxjava2:rxjava:2.1.9'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'

To use RxBinding with Appcompat and other submodules we simply need to import their respective rxbinding libraries:

要将RxBinding与Appcompat和其他子模块一起使用,我们只需要导入它们各自的rxbinding库:

  • implementation com.jakewharton.rxbinding2:rxbinding-recyclerview-v7:2.0.0'

    implementation com.jakewharton.rxbinding2:rxbinding-recyclerview-v7:2.0.0'
  • implementation 'com.jakewharton.rxbinding2:rxbinding-support-v4:2.0.0'

    implementation 'com.jakewharton.rxbinding2:rxbinding-support-v4:2.0.0'
  • implementation 'com.jakewharton.rxbinding2:rxbinding-appcompat-v7:2.0.0'

    implementation 'com.jakewharton.rxbinding2:rxbinding-appcompat-v7:2.0.0'
  • implementation 'com.jakewharton.rxbinding2:rxbinding-design:2.0.0'

    implementation 'com.jakewharton.rxbinding2:rxbinding-design:2.0.0'
  • implementation 'com.jakewharton.rxbinding2:rxbinding-recyclerview-v7:2.0.0'

    implementation 'com.jakewharton.rxbinding2:rxbinding-recyclerview-v7:2.0.0'
  • compile 'com.jakewharton.rxbinding2:rxbinding-leanback-v17:2.0.0'

    compile 'com.jakewharton.rxbinding2:rxbinding-leanback-v17:2.0.0'

we can use RxBinding features in our application.

我们可以在应用程序中使用RxBinding功能。

RxView.click() (RxView.click())

Typically, to set click listener events on a Button, the following is the piece of code that we write:

通常,要在Button上设置点击侦听器事件,以下是我们编写的代码段:

Button b = (Button)findViewById(R.id.button);
b.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(getApplicationContext(),"Button clicked",Toast.LENGTH_SHORT).show();
            }
        });

Now with RxBinding we can do:

现在,使用RxBinding,我们可以执行以下操作:

Disposable d = RxView.clicks(button).
                subscribe(new Consumer<Object>() {
                    @Override
                    public void accept(Object o) {
                     Toast.makeText(getApplicationContext(),"Button clicked",Toast.LENGTH_SHORT).show();
                    }
                });

Inside RxView.clicks we pass the View instance which is to be clicked.

RxView.clicks内部,我们传递了要单击的View实例。

If you are new to RxJava2, Disposable is equivalent to Subscription.
For more information on changes in RxJava2 refer here.

如果您不熟悉RxJava2,则Disposable等同于Subscription。
有关RxJava2中更改的更多信息,请参见此处

On the Disposable instance we can unsubscribe from the event by calling d.dispose();.
The Disposable instance holds a reference to the view. So if this code is defined outside the context of the Activity, you must unsubscribe from the event to prevent memory leaks.

在Disposable实例上,我们可以通过调用d.dispose();取消订阅该事件d.dispose();
Disposable实例包含对该视图的引用。 因此,如果此代码是在Activity上下文之外定义的,则必须取消订阅该事件,以防止内存泄漏。

RxView.click() returns an Observable. So we can add RxJava operators to perform transformations and chain implementations on it.

RxView.click()返回一个Observable。 因此,我们可以添加RxJava运算符以在其上执行转换和链式实现。

EditText TextChanges (EditText TextChanges)

Typically to add text change listeners on an EditText we need to implement the TextWatcher methods:

通常,要在EditText上添加文本更改侦听器,我们需要实现TextWatcher方法:

EditText editText = findViewById(R.id.editText);
editText.addTextChangedListener(new TextWatcher() {
   @Override
   public void beforeTextChanged(CharSequence s, int start, int count, int after) {
   
   }
   
   @Override
   public void onTextChanged(CharSequence s, int start, int before, int count) {
   }
   
   @Override
   public void afterTextChanged(Editable s) {
   
   }
});

Using RxBinding we can do:

使用RxBinding,我们可以执行以下操作:

Disposable d2 = RxTextView.textChanges(editText)
                .subscribe(new Consumer<CharSequence>() {
                    @Override
                    public void accept(CharSequence charSequence) throws Exception {
                        //Add your logic to work on the Charsequence
                    }
                });

We pass the EditText inside RxTextView.textChanges.

我们在RxTextView.textChanges内部传递EditText。

Now let’s see how RxJava operators and transformations give us leverage.

现在,让我们看看RxJava运算符和转换如何给我们带来影响。

使用地图运算符 (Using Map operator)

Using map operator we can change the data that is being sent.
For example, in the EditText we can change the CharSequence to a String

使用地图运算符,我们可以更改正在发送的数据。
例如,在EditText中,我们可以将CharSequence更改为String

Disposable d2 = RxTextView.textChanges(editText)
                .map(charSequence -> charSequence.toString())
                .subscribe(new Consumer<CharSequence>() {
                    @Override
                    public void accept(String string) throws Exception {
                        //Add your logic to work on the Charsequence
                    }
                });

使用反跳运算符 (Using debounce operator)

Using a debounce operator we can delay the event action.

使用反跳运算符,我们可以延迟事件动作。

For example, on the Button click, we can set a debounce of 2 seconds. This will run the operation after 2 seconds:

例如,在“按钮”上单击,我们可以将去抖设置为2秒。 2秒后将运行该操作:

RxView.clicks(button).debounce(2, TimeUnit.SECONDS).
                observeOn(AndroidSchedulers.mainThread()).
                map(o -> button.getText().toString()).
                subscribe(new Consumer<String>() {
                    @Override
                    public void accept(String o) throws Exception {
                        Toast.makeText(getApplicationContext(),o + "was clicked",Toast.LENGTH_SHORT).show();
                    }
                });

A debounce operation doesn’t run on the UI thread. It runs on the computational thread.
Hence you must call the main thread in the observeOn method after that as done above.

反跳操作不在UI线程上运行。 它在计算线程上运行。
因此,如上所述,您必须在此之后在observeOn方法中调用主线程。

A debounce operator is commonly used in EditText, especially in a SearchView to let the user stop typing for a few seconds before running the action/requests.

反跳运算符通常在EditText中使用,尤其是在SearchView中,可以使用户在运行操作/请求之前停止键入几秒钟。

使用节流阀 (Using throttleFirst)

Unlike debounce which delays the action, throttleFirst operator is used in preventing repeated actions within a certain time interval.
ThrottleFirst is useful when it comes to preventing double actions when a Button is repeatedly clicked.

与防抖会延迟动作不同, throttleFirst运算符用于防止在特定时间间隔内重复动作。
ThrottleFirst对于防止重复单击按钮时的双重操作很有用。

RxView.clicks(button).throttleFirst(2, TimeUnit.SECONDS)
                .observeOn(AndroidSchedulers.mainThread()).
                        subscribe(new Consumer<Object>() {
                            @Override
                            public void accept(Object o) {
                                Toast.makeText(getApplicationContext(), "Avoid multiple clicks using throttleFirst", Toast.LENGTH_SHORT).show();
                            }
                        });

In the above code, the Button won’t show a Toast again until after 2 seconds.

在上面的代码中,Button直到2秒后才会再次显示Toast。

Merging Multiple Button click actions

合并多个按钮单击动作

We can merge RxView.click() Observables in the following way:

我们可以通过以下方式合并RxView.click() Observables:

Button button1 = findViewById(R.id.button1);
Button button2 = findViewById(R.id.button2);
Observable<Object> observable1 = RxView.clicks(button1);
Observable<Object> observable1 = RxView.clicks(button2);

Observable.merge(observable1, observable2)
                        .subscribe(new Consumer<Object>() {
                            @Override
                            public void accept(Object o) {
                                //This common logic would be triggered when either of them are clicked
                            }
                        });

Multiple Click Listeners on a Button

一个按钮上的多个单击侦听器

CompositeDisposable compositeDisposable = new CompositeDisposable();

        Observable<Button> clickObservable = RxView.clicks(button).map(o -> button).share();

        Disposable buttonShowToast =
                clickObservable.subscribe(new Consumer<Button>() {
                    @Override
                    public void accept(Button o) throws Exception {
                        Toast.makeText(getApplicationContext(), "Show toast", Toast.LENGTH_SHORT).show();

                    }
                });
        compositeDisposable.add(buttonShowToast);

        Disposable changeButtonText =
                clickObservable.subscribe(new Consumer<Button>() {
                    @Override
                    public void accept(Button o) throws Exception {

                        o.setText("New text");
                    }
                });
        compositeDisposable.add(changeButtonText);

Using the share operator on the RxView.click() observable, both the Disposables created below are run when the button is clicked.

使用可观察到的RxView.click()上的share运算符,单击该按钮时,将同时运行下面创建的两个Disposable。

Let’s merge the above concepts in our Android Application with a few more operators:

让我们在Android应用程序中将以上概念与更多运算符合并:

项目结构 (Project Structure)

(Code)

activity_main.xml

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:app="https://schemas.android.com/apk/res-auto"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <EditText
        android:id="@+id/editText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Enter here!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.35000002" />

    <TextView
        android:id="@+id/txtBelowEditText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="16dp"
        android:text="TextView"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/editText" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/button2"
        app:layout_constraintBaseline_toBaselineOf="@+id/button2"
         />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:text="Button2"
        app:layout_constraintEnd_toStartOf="@+id/button"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/txtBelowButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:text="TextView"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/button2" />

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="24dp"
        android:layout_marginTop="8dp"
        android:src="@android:drawable/ic_input_add"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
         />

    <Button
        android:id="@+id/button3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Simulateneous Actions"
        app:layout_constraintBottom_toTopOf="@+id/fab"
        android:layout_margin="8dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
         />

</android.support.constraint.ConstraintLayout>

MainActivity.java

MainActivity.java

package com.journaldev.androidrxbinding;

import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import com.jakewharton.rxbinding2.view.RxView;
import com.jakewharton.rxbinding2.widget.RxTextView;

import java.util.concurrent.TimeUnit;

import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;

public class MainActivity extends AppCompatActivity {


    Button button, button2, button3;
    FloatingActionButton fab;
    TextView txtBelowEditText, txtBelowButton;
    EditText editText;

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

        button = findViewById(R.id.button);
        button2 = findViewById(R.id.button2);
        button3 = findViewById(R.id.button3);
        fab = findViewById(R.id.fab);
        txtBelowEditText = findViewById(R.id.txtBelowEditText);
        txtBelowButton = findViewById(R.id.txtBelowButton);
        editText = findViewById(R.id.editText);


        Observable<Object> observable1 = RxView.clicks(button2).map(o -> button2);
        Observable<Object> observable2 = RxView.clicks(fab).map(o -> fab);


        Disposable d1 = Observable.merge(observable1, observable2).throttleFirst(2, TimeUnit.SECONDS)
                .observeOn(AndroidSchedulers.mainThread()).
                        subscribe(new Consumer<Object>() {
                            @Override
                            public void accept(Object o) {
                                Toast.makeText(getApplicationContext(), "Avoid multiple clicks using throttleFirst", Toast.LENGTH_SHORT).show();
                                if (o instanceof Button) {
                                    txtBelowButton.setText(((Button) o).getText().toString() + " clicked");
                                } else if (o instanceof FloatingActionButton) {
                                    txtBelowButton.setText("Fab clicked");
                                }
                            }
                        });


        Disposable d = RxView.clicks(button).debounce(5, TimeUnit.SECONDS).
                observeOn(AndroidSchedulers.mainThread()).
                map(o -> button.getText().toString()).
                subscribe(new Consumer<String>() {
                    @Override
                    public void accept(String o) throws Exception {
                        txtBelowButton.setText(o + " was clicked");
                    }
                });


        Disposable d2 = RxTextView.textChanges(editText)
                .filter(s -> s.toString().length() > 6)
                .debounce(2, TimeUnit.SECONDS)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<CharSequence>() {
                    @Override
                    public void accept(CharSequence charSequence) throws Exception {

                        txtBelowEditText.setText(charSequence);
                    }
                });


        CompositeDisposable compositeDisposable = new CompositeDisposable();

        Observable<Button> clickObservable = RxView.clicks(button3).map(o -> button3).share();

        Disposable buttonShowToast =
                clickObservable.subscribe(new Consumer<Button>() {
                    @Override
                    public void accept(Button o) throws Exception {
                        Toast.makeText(getApplicationContext(), "Show toast", Toast.LENGTH_SHORT).show();

                    }
                });
        compositeDisposable.add(buttonShowToast);

        Disposable changeButtonText =
                clickObservable.subscribe(new Consumer<Button>() {
                    @Override
                    public void accept(Button o) throws Exception {

                        o.setText("New text");
                    }
                });
        compositeDisposable.add(changeButtonText);


        

    }


}

In the EditText, we’ve set a filter operator which doesn’t set the input text onto the TextView until the length crosses a threshold.

在EditText中,我们设置了一个filter运算符,直到长度超过阈值时才将输入文本设置到TextView上。

To clear all the Disposables, instead of calling disposable() on each of them separately, we can do the following as well:

要清除所有Disposable,而不是分别对每个Disposable()进行调用,我们还可以执行以下操作:

CompositeDisposable clearAllDisposables = new CompositeDisposable();
        clearAllDisposables.add(d1);
        clearAllDisposables.add(d2);
        clearAllDisposables.add(d);

        clearAllDisposables.clear();

The output of the application in action is given below:

实际应用程序的输出如下:

Notice how many times the FloatingActionButton was clicked. But the Toast was displayed just once.

注意单击FloatingActionButton的次数。 但是吐司只被展示了一次。

This brings an end to this tutorial. You can download the project from the link below:

本教程到此结束。 您可以从下面的链接下载项目:

翻译自: https://www.journaldev.com/22527/android-rxbinding

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值