Android下的定時任務

來源:互聯網
上載者:User

標籤:ice   flags   ide   類型   ems   完成   display   停止   決策   

Android中的定時任務一般有兩種實現方式,一種是使用Java API裡的Timer類,另一種是使用android的Alarm機制。

      這兩種方式在多數情況下都能實作類別似的效果,但Timer有一個明顯的短板,它並不太適用與那些需要長期在後台啟動並執行定時任務。As we know,為了能讓電池更加耐用,每種手機都會有自己的休眠策略:比如手機不用的時候智能的斷開wifi串連,根據光纖強弱自動調節螢幕亮度,根據手機長時間無操作時自動的讓CPU進入到休眠狀態等,當進入休眠狀態時,這就有可能導致Timer中的定時任務無法正常運行。而Alarn機制則不存在這種情況,它具有喚醒CPU的功能,即可以保證每次需要執行定時任務的時候CPU都能正常工作。需要注意的是,這裡的喚醒CPU和喚醒螢幕不是同一個概念,不能混淆。

 

 

Timer類

使用Timer及TimerTask可以在某個時間執行某一個任務。 Timer是一個普通的類,有幾個重要的方法。而TimerTask是一個抽象類別,要使用的時候必須實現它的Run方法。TimerTask的run方法類似於線程的run方法。 我們使用Timer建立一個他的對象,然後使用這對象的schedule方法來完成這種間隔的操作。 schedule方法有三個參數
第一個參數就是TimerTask類型的對象,我們實現TimerTask的run()方法就是要周期執行的一個任務;
第二個參數有兩種類型,第一種是long類型,表示多長時間後開始執行,另一種是Date類型,表示從那個時間後開始執行;
第三個參數就是執行的周期,為long類型。

schedule方法還有一種兩個參數的執行重載,第一個參數仍然是TimerTask,第二個表示為long的形式表示多長時間後執行一次,為Date就表示某個時間後執行一次。  Timer就是一個線程,使用schedule方法完成對TimerTask的調度,多個TimerTask可以共用一個Timer,也就是說Timer對象調用一次schedule方法就是建立了一個線程,並且調用一次schedule後TimerTask是無限制的迴圈下去的,使用Timer的cancel()停止操作。當然同一個Timer執行一次cancel()方法後,所有Timer線程都被終止。 
 1 //true 說明這個timer以daemon方式運行(優先順序低,程式結束timer也自動結束)  2 java.util.Timer timer = new java.util.Timer(true);   3 TimerTask task = new TimerTask() {   4     public void run() {  5         //每次需要執行的代碼放到這裡面。      6     }      7 };   8  9 10 //以下是幾種調度task的方法:  11 12 //time為Date類型:在指定時間執行一次。 13 timer.schedule(task, time);  14 15 //firstTime為Date類型,period為long,表示從firstTime時刻開始,每隔period毫秒執行一次。 16 timer.schedule(task, firstTime, period);     17 18 //delay 為long類型:從現在起過delay毫秒執行一次。  19 timer.schedule(task, delay);  20 21 //delay為long,period為long:從現在起過delay毫秒以後,每隔period毫秒執行一次。  22 timer.schedule(task, delay, period);

 

Alarm機制

1.首先擷取到AlarmManager的執行個體。
AlarmManager manager = (AlarmManager)getSystemService(Context.ALARM_SERVICE)
然後調用AlarmManager的set()方法就可以設定一個定時任務了。long triggerAtTime = SystemClock.elapsedRealtime() + 10 * 100;manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,triggerAtime,pendingIntent);

set()方法中第一個參數是一個整型參數,用於指定AlarmManager的工作類型,有4種值可選,分別是ELAPSED_REALTIME、ELAPSED_REALTIME_WAKEUP、RTC和RTC_WAKEUP。

ELAPSED_REALTIME:表示讓定時任務的觸發時間從系統開機開始算起,但不會喚醒CPU。

ELAPSED_REALTIME_WAKEUP:同樣表示讓定時任務的觸發時間從系統開機時間開始算起,但會喚醒CPU。

RTC:表示讓定時任務的觸發時間從1970年1月1日0點開始算起,但不會喚醒CPU。

RTC_WAKEUP:表示讓定時任務的觸發時間從1970年1月1日0點開始算起,但會喚醒CPU。

使用SystemClock.elapsedRealtime()方法可以擷取到系統開機至今所經曆時間的毫秒數。使用SystemClock.currentTimeMills()方法可以擷取到1970年1月1日0點至今所經曆時間的毫秒數。 第二個參數是定時任務的觸發時間,以毫秒為單位。若第一個參數使用的是ELAPSED_REALTIME或是ELAPSED_REALTIME_WAKEUP那麼這裡傳入開機至今的時間再加上順延強制的時間。若第一個參數使用的是RTC或是RTC_WAKEUP,那麼這裡傳入1970年1月1日0點至今的時間再加上順延強制的時間。 第三個參數是PendingIntent。
pendingIntent是一種特殊的Intent。主要的區別在於Intent的執行立刻的,而pendingIntent的執行不是立刻的。pendingIntent執行的操作實質上是參數傳進來的Intent的操作,但是使用pendingIntent的目的在於它所包含的Intent的操作的執行是需要滿足某些條件的。主要的使用的地方和例子:通知Notificatio的發送,短訊息SmsManager的發送和警報器AlarmManager的執行等等。PendingIntent中getActivity(Context, int, Intent, int) 跳轉到一個activity組件getBroadcast(Context, int, Intent, int) 發送一個廣播組件getService(Context, int, Intent, int) 啟動一個服務元件
View Code

這裡我們一般會調用getService()方法或者getBroadcast()方法來擷取一個能夠執行服務或者廣播的PendingIntent。這樣當定時任務被觸發的時候。服務的onStartCommand()方法或者廣播的onReceive()方法就可以得到執行。

 

如果想要實現一個長時間在後台定時啟動並執行服務該怎麼做呢?

只需要定義一個服務,並將觸發定時任務的代碼寫到onStartCommand()方法中。

 1 @Override 2     public int onStartCommand(Intent intent,int flags, int startId) { 3         new Thread(new Runnable() { 4             @Override 5             public void run() { 6                 //在這裡執行具體邏輯 7             } 8         }).start(); 9         AlarmManager manager = (AlarmManager)getSystemService(ALARM_SERVICE);10         int anHour = 60 * 60 * 1000; //這是一小時的毫秒數。11         long triggerAtTimer = SystemClock.elapsedRealtime() + anHour;12         Intent i = new Intent(this,LongRunningService.class);13         PendingIntent pi = PendingIntent.getService(this,0,i,0);14         manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,triggerAtTimer,pi);15         return super.onStartCommand(intent,flags,startId);16     }

我們首先是在onStartCommand()方法中開啟了一個子線程,這樣就可以在這裡執行具體的邏輯操作了,之所以要在子線程裡執行邏輯操作,是因為邏輯操作也是需要耗時的,如果放在主線程裡執行可能會對

定時任務的準確性造成輕微的影響。

建立線程代碼之後,先是擷取到了AlarmManager的執行個體, 然後定義任務的觸發時間為一個小時後,再使用PendingIntent指定處理定時任務的服務為LongRunningService,最後調用set()方法完成設定。

 

一旦啟動LongRunningService,就會在onStartCommand()方法裡設定了一個定時任務,這樣一個小時後,將會再次啟動LongRunningService。從而形成一個永久的迴圈,保證LongRunningService的onStartCommand()方法可以每隔一個小時就執行一次。

 

如果想要啟動定時服務的時候調用以下代碼即可。

 Intent intent = new Intent(context,LongRunningService.class);    context.startService(intent);

 

需要注意的是,從Android4.4開始,Alarm任務的觸發時間將會變得不準確,有可能會延遲一段時間後任務才能執行,這是系統在耗電性方面的最佳化,系統會自動檢測目前有多少Alarm任務存在,然後將觸發時間相近的幾個任務放在一起執行,這樣就可以大幅度減少CPU被喚醒的次數,從而減少耗電量。

 

如果要求Alarm任務的執行時間必須準確無誤,只需要使用AlarmManager的setExact()方法來替代set()方法。就基本上可以保證任務能夠準時執行了。

 

  

Android下的定時任務

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.