在微信中啸蜜,當(dāng)和別人進(jìn)行聊天時江兢,如果對方正在輸入文字,我們可以看到對方的輸入狀態(tài)雳刺。
如果這時對方將輸入的文字清空或發(fā)送后劫灶,則正在輸入狀態(tài)消失。這個過程是這樣的:
- A向B發(fā)送文字消息掖桦,當(dāng)A輸入文字的EditText有內(nèi)容本昏,A向B發(fā)送一個消息包X,這個消息包X代表著“正在輸入狀態(tài)”枪汪。
再對A的輸入狀態(tài)定時進(jìn)行檢測涌穆,假設(shè)5s檢測一下,如果5s后發(fā)現(xiàn)EditText還是不為空雀久,再發(fā)送消息包X宿稀,如果EditText內(nèi)容為空,發(fā)送另外一個消息包Y赖捌,這個消息包Y代表著“消息發(fā)送取消”祝沸。
如果點擊發(fā)送按鈕,則發(fā)送文本消息包Z。
- B接收A的消息罩锐,當(dāng)B收到消息包X后奉狈,在界面顯示“對方正在輸入”,為防止因為網(wǎng)絡(luò)原因沒有接收到Y(jié)或者Z消息包而一直顯示輸入狀態(tài)涩惑,B會馬上啟動一個定時任務(wù)仁期,代號“TASK”,清空顯示著的發(fā)送狀態(tài)竭恬,這個定時時間會大于A的發(fā)送周期跛蛋,假設(shè)6s。即B接到消息包X后馬上發(fā)送一個6s后清空顯示著的發(fā)送狀態(tài)的TASK痊硕。
如果B在6s內(nèi)接到消息包X赊级,則取消上面的TASK并啟動新的TASK。
如果B在6s內(nèi)沒接到消息包X寿桨,則TASK將輸入狀態(tài)清空此衅。微信中這是顯示的應(yīng)該是A的昵稱强戴。
如果B接收到消息包Y亭螟,則將輸入狀態(tài)清空。
如果B接收到消息包Z骑歹,則將輸入狀態(tài)清空预烙,顯示A發(fā)送的文本消息。
讓TASK在一段時間后執(zhí)行道媚,并且可以在執(zhí)行前取消扁掸。這個時候就可以使用Timer或者ScheduledExecutorService。先講講Timer最域。
Timer##
Timer定時器實際上是個線程谴分,定時調(diào)度所擁有的TimerTask。需要定時執(zhí)行的代碼放到run方法體內(nèi)镀脂。
先看個簡單的例子:
public class ScheduleTask {
static TimerTask task = new TimerTask() {
@Override
public void run() {
System.out.println("Execut Task Time:" + System.currentTimeMillis());
}
};
public static void main(String[] args) {
long beginTime = System.currentTimeMillis();
System.out.println("Application Begin Time:" + beginTime);
Timer timer1 = new Timer();
timer1.schedule(task, 1000);
}
}
執(zhí)行結(jié)果可以看到任務(wù)在延遲1s后執(zhí)行了:
Application Begin Time:1420366178189
Execut Task Time:1420366179190
在Timer類中schedule()方法如下:
Timer.schedule(TimerTask task,Date time)
在制定的時間執(zhí)行指定的任務(wù)
-
Timer.schedule(TimerTask task,Date firstTime ,long period)
在指定的時間開始進(jìn)行牺蹄,之后重復(fù)的延遲執(zhí)行 -
Timer.schedule(TimerTask task,long delay)
在延遲后執(zhí)行任務(wù) -
Timer.schedule(TimerTask task,long delay,long period)
從延遲后開始進(jìn)行,之后重復(fù)的延遲執(zhí)行 -
Timer.scheduleAtFixedRate(TimerTask task,Date firstTime,long period)
任務(wù)在指定的時間開始進(jìn)行重復(fù)的固定速率執(zhí)行 -
Timer.scheduleAtFixedRate(TimerTask task,long delay,long period)
任務(wù)在指定的延遲后開始進(jìn)行重復(fù)的固定速率執(zhí)行
其中schedule與scheduleAtFixedRate的使用還是有區(qū)別的:
schedule:適用于那些需要“平穩(wěn)”運行的重復(fù)執(zhí)行活動薄翅。換句話說沙兰,它適用于在短期運行中保持頻率準(zhǔn)確要比在長期運行中更為重要的活動。這包括大多數(shù)動畫任務(wù)翘魄,如以固定時間間隔閃爍的光標(biāo)鼎天。這還包括為響應(yīng)人類活動所執(zhí)行的固定活動,如在按住鍵時自動重復(fù)輸入字符暑竟。
scheduleAtFixedRate:適用于那些對絕對時間敏感的重復(fù)執(zhí)行活動斋射,如每小時準(zhǔn)點打鐘報時,或者在每天的特定時間運行已安排的維護活動。它還適用于那些完成固定次數(shù)執(zhí)行的總計時間很重要的重復(fù)活動罗岖,如倒計時的計時器怀大,每秒鐘滴答一次,共10 秒鐘呀闻。最后化借,固定速率執(zhí)行適用于安排多個重復(fù)執(zhí)行的計時器任務(wù),這些任務(wù)相互之間必須保持同步捡多。
在Timer類中還有一個比較常用的方法就是cancel()蓖康,用于終止定時任務(wù)。
ScheduledExecutorService##
ScheduledExecutorService有四個方法:
方法與上面的相似垒手,這次就不做解釋了蒜焊,注意看這四個方法返回的類型都為
ScheduledFuture<?>
,而interface ScheduledFuture<V> extends Delayed, Future<V>
所以取消任務(wù)方法在Future
中科贬。直接看例子泳梆,以最開始說的用戶B收到消息X為例,在項目中的用法為:
if (receivedStatus == Presence.STATUS_TEXT){
// 1. 第一次接到STATUS_TEXT榜掌,將abTabTitleText設(shè)置成“對方正在輸入...”
// 2. 4.5s后調(diào)度執(zhí)行showConnectionState (之所以是4.5秒 是因為發(fā)送那邊的間隔是4秒)
// 3. 再次接到STATUS_TEXT优妙,將上一個調(diào)度取消
// 4. 執(zhí)行2調(diào)度
abTabTitleText.setText("對方正在輸入...");
if (textRecevieTaskCount > 0){
cancelTextRecevieFuture();
}
scheduleTextRecevie();
textRecevieTaskCount ++;
收到消息后馬上執(zhí)行scheduleTextRecevie()
方法:
private void scheduleTextRecevie(){
textRecevieTaskFuture = executor.schedule(new Runnable() {
@Override
public void run() {
mainHandler.post(new Runnable() {
@Override
public void run() {
if (textRecevieTaskFuture != null){
showConnectionState();
textRecevieTaskCount = 0;
textRecevieTaskFuture = null;
}
}
});
}
}, 4500L, TimeUnit.MILLISECONDS);
}
取消任務(wù)方法為:
private void cancelTextRecevieFuture(){
if (textRecevieTaskFuture != null){
textRecevieTaskFuture.cancel(true);
textRecevieTaskFuture = null;
}
}