前言
目前市場上的很多app都會(huì)有點(diǎn)擊兩次返回鍵, 才退出app的功能, 以此來避免用戶的誤操作點(diǎn)擊返回鍵退出, 大致的邏輯便是用戶在規(guī)定的時(shí)間內(nèi)點(diǎn)擊兩次返回,第一次點(diǎn)擊提示在點(diǎn)擊一次
最初的解決思路
很自然的會(huì)想到用下列代碼來實(shí)現(xiàn)(查了下網(wǎng)上大部分實(shí)現(xiàn)也是類似下列代碼的思路)
// 這里規(guī)定時(shí)間再2秒內(nèi), 點(diǎn)擊兩次返回
private long lastTime = 0L;
@Override
public void onBackPressed() {
long currentTime = System.currentTimeMillis();
if ((currentTime - lastTime) > 2000) {
// 兩次點(diǎn)擊間隔超過2秒
Toast.makeText(this, "在點(diǎn)擊一次返回", Toast.LENGTH_SHORT).show();
// 記錄時(shí)間
lastTime = currentTime;
} else {
// 兩次點(diǎn)擊再2秒內(nèi), 即退出
super.onBackPressed();
}
}
上述代碼雖然容易想到, 但是實(shí)現(xiàn)起來不夠優(yōu)雅, 需要自己去記錄時(shí)間, 自己去做各種判斷, 如果換個(gè)需求要求2秒內(nèi)點(diǎn)擊三次才退出(只是隨便說說, 也不大可能會(huì)有這種需求), 那上述代碼基本沒法復(fù)用, 且會(huì)出現(xiàn)各種繁瑣的邏輯判斷.
但是如果使用RxJava
來實(shí)現(xiàn)該功能的話, 可以很輕松很優(yōu)雅地解決該問題:
使用RxJava來解決
上述代碼繁瑣的原因在于需要定義一個(gè)變量來判斷當(dāng)前點(diǎn)擊與上一次點(diǎn)擊的時(shí)間差, 而當(dāng)我們把點(diǎn)擊事件變成事件流時(shí), 很自然地就會(huì)相到使用debounce()
轉(zhuǎn)換符來發(fā)射前后兩次點(diǎn)擊大于規(guī)定時(shí)間差的事件, 再將兩個(gè)事件流合并起來處理就很簡單了
// 返回事件流
private Subject<Integer> mBackClick = PublishSubject.create();
@Override
public void onBackPressed() {
mBackClick.onNext(1)
}
public void onCreate(){
// ... 省略代碼
// 返回事件流(1 -> 1 -> 1 -> 1 -> 1 -> 1)與兩次點(diǎn)擊返回間隔大于2s的事件流(0 -> 0)合并
// 變成 (1 -> 0 -> 1 -> 0 -> 1 -> 1 -> 1 -> ...)
mBackClick.mergeWith(mBackClick.debounce(2000, TimeUnit.MILLISECONDS).map(new Function<Integer, Integer>() {
@Override
public Integer apply(Integer i) throws Exception {
// 兩次點(diǎn)擊返回間隔大于2s的事件, 用0表示, 區(qū)分正常的點(diǎn)擊
return 0;
}
}))
// 這一步轉(zhuǎn)化是關(guān)鍵
// 使用一個(gè)scan轉(zhuǎn)換符去做處理, 如何當(dāng)前事件是0, 則返回0
// 否則則是上一個(gè)事件加一(這個(gè)就可以將所有前后間隔小于2s的事件標(biāo)上序號, 方便后序訂閱處理,
// 拿到序號1的事件彈出提示, 拿到序號2的序列做返回, 甚至于可以處理3號, 4號),
// 這樣也就可以毫不費(fèi)力地解決上訴說的要求2秒內(nèi)點(diǎn)擊三次才退出
// 變成 (1 -> 0 -> 1 -> 0 -> 1 -> 2 -> 3 -> ...)
.scan((prev, cur) -> {
if (cur == 0) return 0
return prev + 1
})
// 過濾掉0, 后面我們只關(guān)心拿到的是幾號的時(shí)間
.filter(v -> v > 0)
.subscribe(v -> {
if (v == 1) {
// 彈出提示
} else if (v == 2) {
// 返回
} else if (v == 3) {
..
}
...
})
}
// 真實(shí)實(shí)現(xiàn)里記得取消訂閱
以上即可處理各種在前后間隔n秒內(nèi), 同一個(gè)操作, 根據(jù)順序采取不同的處理方式
總結(jié)
上訴關(guān)鍵的核心就在于使用debounce
生成一個(gè)新的流與原返回流合并, 將所有前后間隔事件小于2s的事件分隔開來, 并使用scan
轉(zhuǎn)化符標(biāo)記上序號, 方便后續(xù)訂閱的處理, 可能畫幾張事件流程圖更容易理解
DEMO
TODO
- [ ] 有空把事件流示意圖畫一下