android創建定時任務

時代會爲你做出選擇,不管你是否願意。

最近的移動端的工作似乎也是到了瓶頸,工作並沒有像15-16年那麼火爆,貌似市場上出現供過於求的狀態,但是沒有必要感覺不安,你有着邏輯基礎,有着基礎能力,閉關幾月在去精通一門技術又何妨?

如果你想要飛,就拼力讓自己的羽翼豐滿,翅膀堅硬,而不只是擁有夢想?

實際上,在開發的過程中,我們經常遇到的情景接收短信驗證碼?

這時候你可以開啓一個線程自己書寫邏輯,也可以使用android的創建定時任務功能。

android定時任務有兩種:

1:Timer類。

2:Alarm機制。

現在具體說說:

Timer:Timer的使用必須和TimerTask結合在一起,如果不太明白可以百度搜索一下使用方法。

CountDownTimer:表示倒計時任務類,很適合實際開發中的接收驗證碼倒計時使用。下面就是這個類的使用:因爲你CountDownTimer是抽象類,所以必須實現裏面的抽象方法

class MyTimer extends CountDownTimer{

/**
* millisInFuture:總時長
* countDownInterval:間隔時長
*/
        public MyTimer(long millisInFuture, long countDownInterval) {
            super(millisInFuture, countDownInterval);
        }

/**
* millisUntilFinished 每次執行倒計時一次該方法就會被觸發,並返回剩餘時長
*/
        @Override
        public void onTick(long millisUntilFinished) {

        }

/**
* 倒計時執行完成的時候觸發的動作
*/
        @Override
        public void onFinish() {

        }
    }

Alarm機制:

在網上搜索最多的還是Timer的使用,對於Alarm機制的講解並不多,但是這裏整理一下:

先看一段代碼:創建一個10s的定時任務

AlarmManager manager = ((AlarmManager) getSystemService(ALARM_SERVICE));

        int time = 10*1000;

        long triggerAtTime = SystemClock.elapsedRealtime()+time;

        Intent i = new Intent(this,AlarmService.class);

        PendingIntent pendingIntent = PendingIntent.getService(this,0,i,0);

        manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,triggerAtTime,pendingIntent);

上面的代碼就是 創建定時任務,但是看着有些蒙,下面說說:

1.創建Alarm定時任務,首先需要AlarmManager對象:

AlarmManager manager = ((AlarmManager) getSystemService(ALARM_SERVICE));

2.調用AlarmManager.set()的方法就可以設置定時任務。

set(int type, long triggerAtMillis, PendingIntent operation)

看看set()方法中的三個參數的意義:

type:指定AlarmManager的工作類型,有一下4中可選:

選擇類型

解釋:

ELAPSED_REALTIME_WAKEUP:定時任務的觸發時間從系統開機的時刻開始算起,同時喚醒CPU。

ELAPSED_REALTIME:也是觸發時間從系統開機的時刻算起,但是不會喚醒CPU

RTC_WAKEUP:定時任務觸發時間從1970年1月1日0點開始算起,同時喚醒CPU

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

所以對於指定方式的不同,會直接影響第二個參數的計算方式:

triggerAtMillis:如果type的取值爲ELAPSED_REALTIME_WAKEUP或者ELAPSED_REALTIME的時候,那麼時間使用

 SystemClock.elapsedRealtime()

獲取開機至今所經歷的毫秒數

如果type的取值爲RTC_WAKEUP或者RTC_WAKEU的時候,那麼時間使用

 System.currentTimeMillis()

獲取1970年1月1日0時至今的時間

operation:是一個PendingIntent廣播中有提到的,當到達觸發時間時,會自動執行PendingIntenet中的邏輯內容。

那我們現在看看上述的代碼,是否能明白寫呢?上述代碼的意義是 以開機時間爲參考,10s之後執行AlarmService的內容。


實踐操作:

需求:每隔10s開啓一個service的服務操作

創建AlarmService如下:

public class AlarmService extends Service {


    int i = 0;

    AlarmManager manager;

    PendingIntent pendingIntent;

    private static final String TAG = "AlarmService";

    public AlarmService() {

    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        Toast.makeText(this,"啓動服務",Toast.LENGTH_SHORT).show();
        Log.i(TAG, "onStartCommand: i------>"+i++);

        manager = ((AlarmManager) getSystemService(ALARM_SERVICE));

        int time = 10*1000;

        long triggerAtTime = SystemClock.elapsedRealtime()+time;

        Intent i = new Intent(this,AlarmService.class);

        pendingIntent = PendingIntent.getService(this,0,i,0);

        manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,triggerAtTime,pendingIntent);

        return super.onStartCommand(intent, flags, startId);
    }
    @Override
    public void onDestroy() {
        super.onDestroy();

        Log.i(TAG, "onDestroy: AlarmManager is cancle");

        manager.cancel(pendingIntent);
    }
    @Override
    public boolean onUnbind(Intent intent) {
        return super.onUnbind(intent);
    }

    @Override
    public void onRebind(Intent intent) {
        super.onRebind(intent);
    }

}

然後創建Actvity中的按鈕來啓動服務和結束服務就好了,但是結束服務之後一定要將alarm進行取消,不然時間一到,Alarm還是會執行服務的啓動的。

public class AlarmActivity extends AppCompatActivity {

    Intent intent;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_alarm);
        intent = new Intent(AlarmActivity.this,AlarmService.class);
        findViewById(R.id.btn_Alarm).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                startService(intent);
            }
        });


        findViewById(R.id.btn_Alarm_stop).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                stopService(intent);
            }
        });
    }
}

我們看一下結果

執行

每隔10s都會盡心一次提示以及輸出。

點擊取消按鈕:

取消服務以及將Alarm進行關閉

再看,關閉服務之後在不會進行輸出,所以成功了。

當然目前的功能還是比較單一,在實際的開發中你可能要用服務進行網絡請求,進行返回數據的判斷等等。


注意:從android4.4開始,Alarm任務的觸發時間將會變得不精準,有可能會拖延一段時間後任務纔回得到執行,但這並不是bug。

而是系統在耗電性方面做得優化,系統會自動檢測目前有多少Alarm任務存在,然後將觸發時間相近的的幾個任務放在一起進行執行,這樣可以大幅度的減少CPU被喚醒的次數,從而延長電池的使用壽命。

當然,如果要求是時間準確無誤,就使用setExact()方法代替set()方法就好。

Doze模式

在android6.0的系統中,google加入Doze模式,目的是延長電池的壽命,如果設備未插電源且屏幕關閉了一段時間後就會進入Doze模式。在Doze模式下系統會對CPU。網絡,以及Alarm等活動進行限制,從而延長電池壽命。

具體看看Doze模式下受限的功能:

網絡訪問被禁止
系統忽略喚醒CPU或者屏幕操作
系統不再執行wifi掃描
系統不再提供同步服務‘
Alarm任務將會在下次退出Doze模式的時候執行

對於Alarm來講,在Doze模式下,我們的Alarm任務將會變得不準時。當然,大多數情況這是可以理解的,因爲只有長時間不適用手機的時候纔會進入Doze模式,但是關於這個長時間是多長沒有具體的說明。

當然如果你有特殊的要求,要求Alarm在Doze模式下也可以正常執行,調用AlarmMananger的setAndAllowWhileIdle()setExactAndAllowWhileIdle()方法就可以讓程序在Doze模式下也可以正常的執行,區別和set()setExact()方法一致

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章