時代會爲你做出選擇,不管你是否願意。
最近的移動端的工作似乎也是到了瓶頸,工作並沒有像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都會盡心一次提示以及輸出。
點擊取消按鈕:
再看,關閉服務之後在不會進行輸出,所以成功了。
當然目前的功能還是比較單一,在實際的開發中你可能要用服務進行網絡請求,進行返回數據的判斷等等。
注意:從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()
方法一致