点击两次返回按钮以使用rxjava退出活动

3
寻找一种微妙的rx方法,在按两次后退按钮时退出活动。
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);
} 
3个回答

4
我建议采用略有不同的方法。实际上,我们所要寻找的是两次点击之间的时间。RxJava拥有interval(TimeUnit)运算符,可以准确地给出我们想要的结果。因此,我们已经确定了主题和期望的退出超时时间。
private static final long EXIT_TIMEOUT = 2000;
private CompositeDisposable compositeDisposable = new CompositeDisposable();
private PublishSubject<Boolean> backButtonClickSource = PublishSubject.create();

在onResume方法中,我们向主题添加操作符并订阅它。我们将结果添加到CompositeDisposable中,以便稍后能够与您在活动中拥有的所有其他订阅一起处理。
@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();
                }
            }));
}

我们使用抖动处理来消除噪音(可能不必要)。然后,每次点击时,我们向用户显示消息(任何你想要的内容,为了简单起见,我使用了Toast)。在切换到主线程之前,否则将抛出异常。我们跳过第一个事件,因为否则将会发出订阅和第一次单击之间的时间间隔,并且如果它足够小,则仅在单击后发生退出。我们过滤掉所有大于我们的EXIT_TIMEOUT的时间间隔。最后,当我们得到足够小的时间间隔时(不是第一个),我们就完成了活动。
然后,在onPause中,我们应该清除我们的CompositeDisposable,以便不再接收到点击事件。
@Override
protected void onPause() {
    super.onPause();

    compositeDisposable.clear();
}

当然,在onBackPressed()方法中,我们应该将后退按钮点击事件转发到我们的PublishSubject。

@Override
public void onBackPressed() {
    backButtonClickSource.onNext(true);
}

2
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) {}
}

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

然后从监听器中将点击事件传递给clickSource,或使用RxBindings库:

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

还有.window()运算符,您可以在第一次单击后打开“事件阀门”以限定时间,并在未收到第二次单击时关闭它。


快速查看这段代码,它不会正常工作 - 您点击返回按钮一次(发出事件),然后5分钟后再次点击(第二个事件),应用程序就会关闭。 - Than
这是为了防止意外点击而设计的。如果您想在一段时间后重置点击,可以引入一些状态,并在每次点击后启动超时任务。 - Alex Shutov
实际上,这里的防抖也是错误的,将n个项目在100ms窗口中发出将导致订阅者仅收到1个项目。 - Than
.debounce() 用于过滤 "抖动" - 当用户戴着手套触摸按钮并且事件生成非常快时。 - Alex Shutov
电子电路使用施密特触发器来实现此功能。 - Alex Shutov
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接