https://blog.csdn.net/weixin_29099729/article/details/117492325
1、普通線程sleep的方式,可用於一般的輪詢Polling
new Thread(new Runnable() { @Override public void run() { while (true) { //todo try { Thread.sleep(iDelay); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start();
優點:非常簡單的實現,邏輯清晰明了,也是最常見的寫法
缺點:在sleep結束后,並不能保證競爭到cpu資源,這也就導致了下次執行時間必定>=iDelay,存在時間精度問題
2、Timer定時器
//Timer + TimerTask結合的方法 private final Timer timer = new Timer(); private TimerTask timerTask = new TimerTask() { @Override public void run() { //todo } };
啟動定時器方法:
timer.schedule(TimerTask task, long delay, long period)
立即執行
timer.schedule(timerTask, 0, 1000); //立刻執行,間隔1秒循環執行
延時執行
timer.schedule(timerTask, 2000, 1000); //等待2秒后再執行,間隔1秒循環執行
關閉定時器方法:timer.cancel();
優點:純正的定時任務,純java SDK,單獨線程執行,比較安全,而且還可以在運行過程中取消執行
缺點:基於單線程執行,多個任務之間會相互影響,多個任務的執行是串行的,性能較低,而且timer也無法保證時間精確度,是因為手機休眠的時候,無法喚醒cpu,不適合后台任務的定時
3、ScheduledExecutorService
private Runnable runnable2 = new Runnable() { @Override public void run() { //todo } }; ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); executor.scheduleAtFixedRate(runnable2, 0, 1, TimeUnit.SECONDS);
關於scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) 方法說明:
command:需要執行的線程
initialDelay:第一次執行需要延時的時間,如若立即執行,則initialDelay = 0
period:固定頻率,周期性執行的時間
unit:時間單位,常用的有MILLISECONDS、SECONDS和MINUTES等,需要注意的是,這個單位會影響initialDelay和period,如果unit = MILLISECONDS,則initialDelay和period傳入的是毫秒,如果unit = SECONDS,則initialDelay和period傳入的是秒
補充一下: 還有一個方法跟上面的很相似:scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit),這個也是帶延遲時間的調度,並且也是循環執行,唯一的不同就是固定延遲時間循環執行,上面的是固定頻率的循環執行。那這兩者的區別?
舉例子:
使用scheduleAtFixedRate,任務初始延遲3秒,任務執行3秒,任務執行間隔為5秒:
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); Log.e(TAG, "schedule just start! time =" + simpleDateFormat.format(System.currentTimeMillis())); executor.scheduleAtFixedRate(new Runnable() { @Override public void run() { SystemClock.sleep(3000L); Log.e(TAG, "runnable just do it! time =" + simpleDateFormat.format(System.currentTimeMillis())); } }, 3, 5, TimeUnit.SECONDS);
執行結果截圖:
使用scheduleWithFixedDelay,任務初始延遲3秒,任務執行3秒,任務執行延遲為5秒:
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); Log.e(TAG, "schedule just start! time =" + simpleDateFormat.format(System.currentTimeMillis())); executor.scheduleWithFixedDelay(new Runnable() { @Override public void run() { SystemClock.sleep(3000L); Log.e(TAG, "runnable just do it! time =" + simpleDateFormat.format(System.currentTimeMillis())); } }, 3, 5, TimeUnit.SECONDS);
執行結果截圖:
從這兩者的運行結果就可以看到區別了:scheduleAtFixedRate是相對於任務執行的開始時間,而scheduleWithFixedDelay是相對於任務執行的結束時間。
優點:ScheduledExecutorService是一個線程池,其內部使用的延遲隊列,本身就是基於等待/喚醒機制實現的,所以CPU並不會一直繁忙。解決了Timer&TimerTask存在的問題,多任務處理時效率高
缺點:取消時需要打斷線程池的運行,而且和外界的通信不太好處理
4、使用Handler中的postDelayed方法
private Handler mHandler = new Handler(); private Runnable runnable = new Runnable() { @Override public void run() { //todo mHandler.postDelayed(this, iDelay); } }; mHandler.post(runnable); //立即執行 mHandler.postDelayed(runnable, iDelay); //延時執行 mHandler.removeCallbacks(runnable); //取消執行
優點:比較簡單的android實現,適用UI線程
缺點:沒想到,手動捂臉。。。。我估計是使用不當會造成內存泄露吧
5、Service + AlarmManger + BroadcastReceiver
本人非常推薦使用這種方式,適用於長期或者有精確要求的定時任務。我專門為這部分內容寫過一篇博客,傳送門:Android 定時任務之Service + AlarmManger + BroadcastReceiver