单击后退按钮两次以使用 rxjava 退出 activity
Clicking back button twice to exit an activity with rxjava
寻找一种微妙的 rx 方法来退出 activity 同时按两次后退按钮。
boolean doubleBackToExitPressedOnce = false;
@Override
public void onBackPressed() {
if (doubleBackToExitPressedOnce) {
super.onBackPressed();
return;
}
this.doubleBackToExitPressedOnce = true;
Toast.makeText(this, "Please click BACK again to exit", Toast.LENGTH_SHORT).show();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
doubleBackToExitPressedOnce=false;
}
}, 2000);
}
PublishSubject<Boolean> clickSource = PublishSubject.create();
clickSource.debounce(100, TimeUnit.MILLISECONDS)
.take(2)
.subscribe(t -> MyActivity.this.finish()};
然后从侦听器或使用 RxBindings 库将点击事件提供给 clickSource:
btnExit.setOnClickListener(v -> clickSource.onNext(true));
还有 .window() 运算符,您可以使用它在第一次点击后打开 'event valve' 有限的时间,如果没有收到第二次点击则关闭它
我会建议稍微不同的方法。实际上,我们正在寻找的是两次点击之间的时间。 RxJava 有运算符 interval(TimeUnit),它给了我们想要的东西。
所以,我们有我们的主题和期望的退出超时。
private static final long EXIT_TIMEOUT = 2000;
private CompositeDisposable compositeDisposable = new CompositeDisposable();
private PublishSubject<Boolean> backButtonClickSource = PublishSubject.create();
在 onResume 中,我们将运算符添加到我们的主题并订阅它。我们将结果添加到 CompositeDisposable,以便稍后能够将其与您可能在 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();
}
}));
}
我们使用 debounce 来消除噪音(可能是不必要的)。然后在每次点击时我们向用户显示消息(无论你想要什么,为了简单起见,我使用了 Toast)。在我们切换到主线程之前,否则会抛出异常。我们跳过第一个事件,因为否则将发出订阅和第一次点击之间的时间间隔,如果它足够小,只需单击一次就会退出。我们过滤掉所有大于 EXIT_TIMEOUT 的间隔。最后,当我们得到足够小的时间间隔时,这不是第一次,我们完成了 activity.
然后,在 onPause 中我们应该清除我们的 CompositeDisposable 以便不再获取点击事件。
@Override
protected void onPause() {
super.onPause();
compositeDisposable.clear();
}
当然,在 onBackPressed() 中,我们应该将后退按钮点击转发到我们的 PublishSubject。
@Override
public void onBackPressed() {
backButtonClickSource.onNext(true);
}
private Disposable backPressedDisposable;
private BehaviorSubject<Long> backPressedSubject = BehaviorSubject.createDefault(0L); // init with 0
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
backPressedDisposable = backPressedSubject
.buffer(2, 1)
.map(it -> new Pair<>(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();
}
});
}
@Override
public void onBackPressed() {
backPressedSubject.onNext(System.currentTimeMillis()); // add current time
}
@Override
protected void onDestroy() {
super.onDestroy();
try {
backPressedDisposable.dispose();
} catch (Exception ignore) {}
}
寻找一种微妙的 rx 方法来退出 activity 同时按两次后退按钮。
boolean doubleBackToExitPressedOnce = false;
@Override
public void onBackPressed() {
if (doubleBackToExitPressedOnce) {
super.onBackPressed();
return;
}
this.doubleBackToExitPressedOnce = true;
Toast.makeText(this, "Please click BACK again to exit", Toast.LENGTH_SHORT).show();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
doubleBackToExitPressedOnce=false;
}
}, 2000);
}
PublishSubject<Boolean> clickSource = PublishSubject.create();
clickSource.debounce(100, TimeUnit.MILLISECONDS)
.take(2)
.subscribe(t -> MyActivity.this.finish()};
然后从侦听器或使用 RxBindings 库将点击事件提供给 clickSource:
btnExit.setOnClickListener(v -> clickSource.onNext(true));
还有 .window() 运算符,您可以使用它在第一次点击后打开 'event valve' 有限的时间,如果没有收到第二次点击则关闭它
我会建议稍微不同的方法。实际上,我们正在寻找的是两次点击之间的时间。 RxJava 有运算符 interval(TimeUnit),它给了我们想要的东西。 所以,我们有我们的主题和期望的退出超时。
private static final long EXIT_TIMEOUT = 2000;
private CompositeDisposable compositeDisposable = new CompositeDisposable();
private PublishSubject<Boolean> backButtonClickSource = PublishSubject.create();
在 onResume 中,我们将运算符添加到我们的主题并订阅它。我们将结果添加到 CompositeDisposable,以便稍后能够将其与您可能在 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();
}
}));
}
我们使用 debounce 来消除噪音(可能是不必要的)。然后在每次点击时我们向用户显示消息(无论你想要什么,为了简单起见,我使用了 Toast)。在我们切换到主线程之前,否则会抛出异常。我们跳过第一个事件,因为否则将发出订阅和第一次点击之间的时间间隔,如果它足够小,只需单击一次就会退出。我们过滤掉所有大于 EXIT_TIMEOUT 的间隔。最后,当我们得到足够小的时间间隔时,这不是第一次,我们完成了 activity.
然后,在 onPause 中我们应该清除我们的 CompositeDisposable 以便不再获取点击事件。
@Override
protected void onPause() {
super.onPause();
compositeDisposable.clear();
}
当然,在 onBackPressed() 中,我们应该将后退按钮点击转发到我们的 PublishSubject。
@Override
public void onBackPressed() {
backButtonClickSource.onNext(true);
}
private Disposable backPressedDisposable;
private BehaviorSubject<Long> backPressedSubject = BehaviorSubject.createDefault(0L); // init with 0
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
backPressedDisposable = backPressedSubject
.buffer(2, 1)
.map(it -> new Pair<>(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();
}
});
}
@Override
public void onBackPressed() {
backPressedSubject.onNext(System.currentTimeMillis()); // add current time
}
@Override
protected void onDestroy() {
super.onDestroy();
try {
backPressedDisposable.dispose();
} catch (Exception ignore) {}
}