Skip to content Skip to sidebar Skip to footer

Clicking Back Button Twice To Exit An Activity With Rxjava

Looking for a subtle rx approach to exit an activity while pressing back button two times. boolean doubleBackToExitPressedOnce = false; @Override public void onBackPressed() {

Solution 1:

I would suggest slightly different approach. Actually, what we are looking for, is time between 2 clicks. RxJava has operator interval(TimeUnit), which gives us exactly what we want. So, we have our subject and desired exit timeout.

privatestaticfinallongEXIT_TIMEOUT=2000;
privateCompositeDisposablecompositeDisposable=newCompositeDisposable();
private PublishSubject<Boolean> backButtonClickSource = PublishSubject.create();

In onResume we add operators to our subject and subscribe to it. Result we are adding to CompositeDisposable, to be able to dispose it later with all other subscriptions you probably have in your activity.

@Override
protected void onResume() {
    super.onResume();

    compositeDisposable.add(backButtonClickSource
            .debounce(100, TimeUnit.MILLISECONDS)
            .observeOn(AndroidSchedulers.mainThread())
            .doOnNext(new Consumer<Boolean>() {
                @Override
                public void accept(@NonNull Boolean event) throws Exception {
                    Toast.makeText(MainActivity.this, "Please press back once more to exit", Toast.LENGTH_SHORT).show();
                }
            })
            .timeInterval(TimeUnit.MILLISECONDS)
            .skip(1)
            .filter(new Predicate<Timed<Boolean>>() {
                @Override
                public boolean test(@NonNull Timed<Boolean> interval) throws Exception {
                    return interval.time() < EXIT_TIMEOUT;
                }
            })
            .subscribe(new Consumer<Timed<Boolean>>() {
                @Override
                public void accept(@NonNull Timed<Boolean> interval) throws Exception {
                    finish();
                }
            }));
}

We use debounce to get rid of noise (maybe unnecessary). Then on each click we show message to user (whatever you want, for sake of simplicity I used Toast). Before we switch to main thread, otherwise exception will be thrown. First event we skip, because otherwise time interval between subscribe and first click will be emitted, and if it's small enough, exit will happen after just one click. All the intervals that are bigger than our EXIT_TIMEOUT we filter out. And finally, when we get small enough time interval, which is not first, we finish our activity.

Then, in onPause we should clear our CompositeDisposable in order not to get click events anymore.

@OverrideprotectedvoidonPause() {
    super.onPause();

    compositeDisposable.clear();
}

And of course in onBackPressed() we should forward back button clicks to our PublishSubject.

@OverridepublicvoidonBackPressed() {
    backButtonClickSource.onNext(true);
}

Solution 2:

privateDisposable backPressedDisposable;
privateBehaviorSubject<Long> backPressedSubject = BehaviorSubject.createDefault(0L); // init with 0@OverrideprotectedvoidonCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);

 backPressedDisposable = backPressedSubject
   .buffer(2, 1)
   .map(it -> newPair<>(it.get(0), it.get(1)))
   .map(pair -> pair.second - pair.first < TimeUnit.SECONDS.toMillis(2)) // 2 second
   .observeOn(AndroidSchedulers.mainThread())
   .subscribe(willFinish -> {
     if (willFinish) {
       finish();
     }
     else {
       Toast.makeText(getApplicationContext(), "press once more will exit", Toast.LENGTH_SHORT).show();
     }
   });
}

@OverridepublicvoidonBackPressed() {
 backPressedSubject.onNext(System.currentTimeMillis()); // add current time
}

@OverrideprotectedvoidonDestroy() {
 super.onDestroy();

 try {
   backPressedDisposable.dispose();
 } catch (Exception ignore) {}
}

Solution 3:

PublishSubject<Boolean> clickSource = PublishSubject.create();
clickSource.debounce(100, TimeUnit.MILLISECONDS)
.take(2)
.subscribe(t -> MyActivity.this.finish()};

Then feed click events to clickSource from listener or use RxBindings library:

btnExit.setOnClickListener(v -> clickSource.onNext(true));

There is also .window() operator you can use for opening 'event valve' for a limited time after first click and closing it if second click not received

Post a Comment for "Clicking Back Button Twice To Exit An Activity With Rxjava"