Android轮训机制以及API19之后定时不准的一种解决方案

在项目的进展中,使用到了定时轮训机制,参考网上的一个例子,稍加修改后可以使用,但是发现在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打印的日志:


Android轮训机制以及API19之后定时不准的一种解决方案
文章图片
Android轮训机制以及API19之后定时不准的一种解决方案
文章图片






每隔5秒钟执行一次,基本达到了效果(这里运行时候有一个BUG暂时还没有解决,程序中我设定的时间间隔并是不是5秒,而是2秒,后来不管我怎么改这个间隔,
模拟器运行出来的结果都是5秒,这个问题很头痛,当时在硬件上调试的时候是没问题的,关于这个BUG后面研究好了再补上)




【Android轮训机制以及API19之后定时不准的一种解决方案】



    推荐阅读