Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RxJava - how to invoke subscriber on 4 click events in Android

In android I have a text view defined like this:

<TextView
     android:id="@+id/text1"       
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:text="@string/hello_world"
     android:textColorHighlight="#000000"
     android:textIsSelectable="true" />

My goal is that after it is clicked 4 times, I want to start a new activity. I need to do this with RXJava; this is a requirement. Or rxAndroid, rxBinding, etc.

My activity looks like this:

public class MainActivity extends Activity implements onClickListener {
    TextView tv;
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv=(TextView)findViewById(R.id.text1);
        tv.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        if(v.getId() == R.id.text1){

        }
    }
}

UPDATE: but this is just the standard way of doing it. There must be a way to do with with reactive rxJava API.

So instead of using a onClicklistener with rxBinding I read we can do this:

RxView.clicks(tv).flatMap(tv -> { 
        // another observable which can throw onError. 
        return Observable.error(null); 
    }).subscribe(object -> { 
        Log.d("CLICK", "textview clicked", start activity);
    }, error -> { 
        Log.d("CLICK", "ERROR");
    });

Can I somehow use a command in rxBinding to make it execute only after 4 clicks? I'm not looking to store a static variable, or use a anonymous class and store a member variable for count in it. There should be an observable method for this.

like image 691
j2emanue Avatar asked Jan 19 '16 15:01

j2emanue


2 Answers

You can achieve with something like this:

Observable.create((Observable.OnSubscribe<Void>) subscriber -> {
    if (!subscriber.isUnsubscribed()) {
        button.setOnClickListener(v -> subscriber.onNext(null));
    }
}).buffer(1000, TimeUnit.MILLISECONDS)
        .filter(clicks -> clicks.size() == 4)
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(clicks -> {
            Log.d("CLICK", "CLICK");
        });
  • buffer() - gather clicks for 1s window
  • filter() - filter all emitted buffered items, where is number of items in buffer not equal 4 (disable double, triple, quintuple clicks)

The hardest part is to specify buffer time "window". One second is sometimes not enough, but in other cases user have to wait few milliseconds.

like image 87
skywall Avatar answered Nov 16 '22 00:11

skywall


You could create an observable to emit each time the button is clicked, then count the total times it has emitted, and use a filter so that your subscriber will only see it once it has emitted four times.

Observable<View> buttonObservable = ViewObservable.clicks(initiateButton, false);
buttonObservable.count()
        .filter(count -> (count >= 4))
        .subscribe(object -> {
            //Your code here
        });
like image 42
TheoKanning Avatar answered Nov 16 '22 02:11

TheoKanning