很多时候,我们需要在 android 程序中 制造一个不被杀死的 轮询 监听机制,很容易想到的就是:
1. 线程中while 循环 ,然后 sleep
2. Timer 定时器
对于以上两个方式的做法,对于 线程而言,sleep 并不一定能得到准确的 时间 间隔,所以 1 对于有严格时间间隔要求来说,直接放弃使用
对于 2. 而言 时间间隔可以得到有效保证,但 它和 1 都要一个致命问题,那就是 手机 一旦 黑屏,循环 监听就不会工作
因此,今天我们要讲的就是 android中特有的 定时器 AlarmManager。
下面附上 AlarmManager 的 使用,
public class Polling {
private static final long RECYCLE_TIME=1000 * 60 *1;//循环时间间隔
private static final String ACTION_TAG="com.ishangbin.shop.heartbeat.Polling";
private AlarmManager manager;
private Intent mIntent;
private PendingIntent mPendingIntent;
@SuppressLint("NewApi")
public void start() {
cancel();
// 获取AlarmManager系统服务
manager = (AlarmManager) BaseApplication.getInstance().getSystemService(Context.ALARM_SERVICE);
// 包装需要执行Service的Intent
mIntent = new Intent(BaseApplication.getInstance(), HeartService.class);
mIntent.setAction(ACTION_TAG);
mPendingIntent = PendingIntent.getService(BaseApplication.getInstance(), 0, mIntent,PendingIntent.FLAG_UPDATE_CURRENT);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
manager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()+RECYCLE_TIME, mPendingIntent);
}else{
manager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), RECYCLE_TIME, mPendingIntent);
}
}
public void cancel() {
// 取消正在执行的服务
if(manager!=null&&mPendingIntent!=null){
manager.cancel(mPendingIntent);
}
}
}
此处 HeartService 为 服务,当 AlarmManager 启动的是服务时,调用的是
mPendingIntent = PendingIntent.getService(BaseApplication.getInstance(), 0, mIntent,PendingIntent.FLAG_UPDATE_CURRENT);
若 启动的是 广播 则为
mPendingIntent = PendingIntent.getBroadcast(BaseApplication.getInstance(), 0, mIntent,PendingIntent.FLAG_UPDATE_CURRENT);
然后是 AlarmManager 有两种计时标准 ,分别是 ELAPSED 计时方式(相对时间)和 RTC (自1970年开始计时)的方式,设置 AlarmManager 要注意,当你使用一种计时方式时,就只用这一种,不可两种混用
AlarmManager .set ( , , , ,) 中第一个参数有不同设置,此处设置的是
AlarmManager.RTC_WAKEUP
表示 手机在,黑屏,锁屏时,定时器依然工作,即 cpu唤醒,屏幕唤醒工作。
最后需要注意的是 start 闹钟的 PendingIntent 要和 cancel 的 PendingIntent 保持一致,才能 cancel 掉对应的 AlarmManager
oh,no!android api 19 以后 AlarmManager 的 setRepeating 方法失效,那么我们只有通过 不断的 重复设置 AlarmManager .set ( , , , ,) 方法来实现轮询
OK,讲了这些,回到主题,我们要实现 闹钟的 轮询,再看看 HeartService 服务中的 处理
@Override
protected void onHandleIntent(Intent intent) {
//获取app开启状态
boolean isAlive=Cacher.getInstance().getAppStateTag();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT&&isAlive) {
mPolling.start();
}
if(!isAlive){
mPolling.cancel();
}
L.i("===+++= 执行一次心跳 =+++===" + DateUtil.getNowTime());
if (!NetUtil.isNetConnected()) {
L.i("======心跳 网络异常=====" + DateUtil.getNowTime());
return;
} else {
L.i("======心跳 网络正常=====" + DateUtil.getNowTime());
}
//......执行后续逻辑
}
HeartService 继承的 是 IntentService,然后在
onHandleIntent
方法中,首先判断 当前 api 是否 大于 19,若大于则再次执行一次 set 方法,到此实现了一个轮询机制。
好的,再看下 在 activity 中的调用
private AlarmReceiver mAlarmReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initData();
setListener();
}
private void initView() {
mButton=(Button) findViewById(R.id.button1);
mImageView=(ImageView) findViewById(R.id.imv_head);
mTvUserName=(TextView) findViewById(R.id.tv_user_name);
}
private void initData() {
mAlarmReceiver=new AlarmReceiver();
}
private void setListener() {
mButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Log.i("","====咳嗽ihi======"+DateUtil.getNowTime());
mAlarmReceiver.start(MainActivity.this);
}
});
}
@Override
protected void onDestroy(){
mAlarmReceiver.cancel();
super.onDestroy();
}
在 MainActivity 中 的 button 中开启定时器,然后在退出时 cancel 掉
当然,最后不能在 mainfast。xml 中忘记 服务的注册:
<!-- 心跳服务 -->
<service android:name="com.ishangbin.shop.heartbeat.HeartService" />
对于 AlarmManager 的 一些基本用法,今天就讲到这里吧