时代会为你做出选择,不管你是否愿意。
最近的移动端的工作似乎也是到了瓶颈,工作并没有像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()
方法一致