在項目的進展中,使用到了定時輪訓機制,參考網上的一個例子,稍加修改後可以使用,但是發現在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後面研究好了再補上)