理論上,android系統休眠後,app進程會被掛起,所以相關的執行線程也會被掛起,那些java線程的操作例如:wait,await,sleep,循環阻塞,handler的delay,線程池的delay操作都會被掛起,因爲它們使用的系統計時器在休眠的時候是停止的,例如:SystemClock.uptimeMillis(),其實針對不同版本的android系統這些表現各有不同,有些android系統是休眠後這些計時變慢了,原先計時5秒的,休眠後可能要計時5到6分鐘,在android系統中AlarmManager可以解決上述問題,鬧鐘在系統休眠的時候也會喚醒系統的,鬧鐘使用的計時器在休眠的時候是繼續跑的,例如:SystemClock.elapsedRealtime(),但是鬧鐘的計時並不是很準確,甚至有秒級別的誤差:
1. setRepeating方法是重複的喚醒操作,根據api文檔可知系統會對這些做優化,喚醒時間並不會嚴格的按照你設置的參數時間來執行
2. set方法在sdk版本低於19的實現是嚴格準確的按照設置的時間喚醒的,但是在sdk版本高於或者等於19的實現是經過優化的,並不會準確按照設置的時間喚醒,所謂的優化就是系統有可能判斷到間隔時間很小的有兩個鬧鐘喚醒操作,這時候系統可能就會自動的把比較早的那個鬧鐘喚醒操作和比較晚的喚醒操作合併爲一個
3. 根據api文檔說明,想要精確按照設置時間喚醒可採用setExact方法,但是據我真機(小米4C,6.0系統)實測,這個方法的喚醒任然存在較大誤差,誤差甚至到秒級別,有的會誤差幾秒鐘,只能說基本準確
下面是測試代碼:
補充一點:要把alarm和其他的定時測試分開執行,alarm喚醒之後會影響其他線程的測試的
public class MainActivity extends AppCompatActivity {
ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
int i = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "sss", Toast.LENGTH_SHORT).show();
}
});
scheduledExecutorService.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
String format = new SimpleDateFormat("HH:mm:ss").format(new Date());
NotificationUtil.showNotification(MainActivity.this, new Intent(), 100, "ScheduledExecutorService休眠測試", format + ":ScheduledExecutorService執行");
i++;
}
}, 20, 20, TimeUnit.SECONDS);
new Thread() {
@Override
public void run() {
long now;
while (true) {
now = SystemClock.elapsedRealtime();
while (SystemClock.elapsedRealtime() - now < 20000) ;
String format = new SimpleDateFormat("HH:mm:ss").format(new Date());
NotificationUtil.showNotification(MainActivity.this, new Intent(), 101, "Thread休眠測試", format + ":Thread執行");
}
}
}.start();
new Thread() {
@Override
public void run() {
while (true) {
synchronized (this) {
try {
this.wait(20000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
String format = new SimpleDateFormat("HH:mm:ss").format(new Date());
NotificationUtil.showNotification(MainActivity.this, new Intent(), 102, "wait休眠測試", format + ":wait執行");
}
}
}.start();
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
sendEmptyMessageDelayed(1, 20000);
if (msg.what == 1) {
String format = new SimpleDateFormat("HH:mm:ss").format(new Date());
NotificationUtil.showNotification(MainActivity.this, new Intent(), 103, "handler休眠測試", format + ":handler執行");
}
}
};
handler.sendEmptyMessageDelayed(1, 20000);
new Thread(){
@Override
public void run() {
while (true) {
try {
sleep(20000);
} catch (InterruptedException e) {
e.printStackTrace();
}
String format = new SimpleDateFormat("HH:mm:ss").format(new Date());
NotificationUtil.showNotification(MainActivity.this, new Intent(), 104, "sleep休眠測試", format + ":sleep執行");
}
}
}.start();
startService(new Intent(this, TestService.class));
}
}
public class TestService extends Service {
ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
HandlerThread handlerThread = new HandlerThread("ht");
handlerThread.start();
Handler handler = new Handler(handlerThread.getLooper());
handler.post(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(20000);
} catch (InterruptedException e) {
e.printStackTrace();
}
scheduledExecutorService.schedule(new Runnable() {
@Override
public void run() {
String format = new SimpleDateFormat("HH:mm:ss").format(new Date());
NotificationUtil.showNotification(TestService.this, new Intent(), 105, "Service休眠測試", format + ":Service執行");
}
}, 0, TimeUnit.SECONDS);
}
}
});
Intent intent = new Intent(this, InnerGuardReceiver.class);
intent.setAction("com.xtc.watch.guard.push");
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, -1001, intent, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + 20000, 20000, pendingIntent);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
public static class InnerGuardReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String format = new SimpleDateFormat("HH:mm:ss").format(new Date());
NotificationUtil.showNotification(context, new Intent(), 106, "alarm休眠測試", format + ":alarm執行");
}
}
}
上面除了alarm會按時喚醒執行,其他的在手機休眠後計時變慢了,休眠越久,誤差時間就拉的越大,都是20秒的定時任務,休眠後,除了alarm,其他的誤差慢慢變大,例如一開始是30秒,然後1分鐘,3分鐘,5分鐘,10分鐘,16分鐘等等,但是這些計時延遲的時間都基本一直,說明除了alarm,其他使用的系統計時器都是一致的