在项目的进展中,使用到了定时轮训机制,参考网上的一个例子,稍加修改后可以使用,但是发现在5.x的系统上有定时不准的问题,
网上说从API19开始,alarm的机制都是非准确传递的,所以如果还是使用了setRepeating()方法,将会出现定时不准,但是如果强行
想用的话也还是有解决办法的,下面我给出我在项目中用到的例子,希望能给大家一些想法,本人也是菜鸟一枚
希望大神勿喷。
轮训机制的工具类封装参考《android轮询最佳实践service+AlarmManager+Thread》
不想移步的可以看下面的,我将其命名为AlarmUtil
public class AlarmUtil {
// 开启轮询服务
public static void startPollingService(Context context, int seconds,
Class> cls, String action) {
// 获取AlarmManager系统服务
AlarmManager manager = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE);
// 包装需要执行Service的Intent
Intent intent = new Intent(context, cls);
intent.setAction(action);
PendingIntent pendingIntent = PendingIntent.getService(context, 0,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
// 触发服务的起始时间
long triggerAtTime = SystemClock.elapsedRealtime();
// 这里要注意,如果API>=19,就不能再使用setRepeating,应该改为setWindow
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
manager.setWindow(AlarmManager.RTC_WAKEUP, triggerAtTime,
seconds * 1000, pendingIntent);
} else {
// 使用AlarmManger的setRepeating方法设置定期执行的时间间隔(seconds秒)和需要执行的Service
manager.setRepeating(AlarmManager.RTC_WAKEUP, triggerAtTime,
seconds * 1000, pendingIntent);
}
}
// 停止轮询服务
public static void stopPollingService(Context context, Class> cls,
String action) {
AlarmManager manager = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, cls);
intent.setAction(action);
PendingIntent pendingIntent = PendingIntent.getService(context, 0,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
// 取消正在执行的服务
manager.cancel(pendingIntent);
}
}
在原作者的基础上做了些改动,可以看《Android API 19 及以上版本AlarmManager setRepeating 不准或只执行一次的解决方案》
// 这里要注意,如果API>=19,就不能再使用setRepeating,应该改为setWindow
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
manager.setWindow(AlarmManager.RTC_WAKEUP, triggerAtTime,
seconds * 1000, pendingIntent);
} else {
// 使用AlarmManger的setRepeating方法设置定期执行的时间间隔(seconds秒)和需要执行的Service
manager.setRepeating(AlarmManager.RTC_WAKEUP, triggerAtTime,
seconds * 1000, pendingIntent);
}
我这里对应的MainActivity比较简单,两个按钮,一个启动轮训,一个停止轮训,文本框用来显示状态
public class MainActivity extends Activity implements OnClickListener {
// 注册Service时候对应的Action
private final static String SERVIE_ACTION = "myAlarmService";
private Button btn_start;
private Button btn_stop;
private TextView tv_msg ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv_msg = (TextView) findViewById(R.id.tv_msg);
btn_start = (Button) findViewById(R.id.btn_start);
btn_stop = (Button) findViewById(R.id.btn_stop);
btn_start.setOnClickListener(this);
btn_stop.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.btn_start: // 启动定时轮训
tv_msg.setText("启动轮训……");
AlarmUtil.startPollingService(this, 1, MyService.class,
SERVIE_ACTION);
break;
case R.id.btn_stop: // 关闭定时轮训
tv_msg.setText("停止轮训!");
AlarmUtil.stopPollingService(this, MyService.class, SERVIE_ACTION);
break;
default:
break;
}
}
@Override
protected void onPause() {
// 除非有必要一直在后台运行,否则最好在Activity停止或销毁的时候停止轮训服务
AlarmUtil.stopPollingService(this, MyService.class, SERVIE_ACTION);
super.onPause();
}
}
下面重点看运行时候log打印的日志:
每隔5秒钟执行一次,基本达到了效果(这里运行时候有一个BUG暂时还没有解决,程序中我设定的时间间隔并是不是5秒,而是2秒,后来不管我怎么改这个间隔,
模拟器运行出来的结果都是5秒,这个问题很头痛,当时在硬件上调试的时候是没问题的,关于这个BUG后面研究好了再补上)