之前開發的一款運行在定制Android設備上的一個實時監控程序發生了一個很奇怪的問題:關機狀態下放置了半個月左右的時間之后,再次開機使用,使用到一半的時候,顯示界面就卡死在某一個狀態下了(顯示界面只顯示一行文字,代表當前的狀態)。取到的log信息里沒有任何錯誤信息,測試也很難再現問題(因為條件較難滿足,關機狀態下放置半個月)。之后就各種查問題......
終于找到是Timer的問題:如果在啟動一個Timer任務之后,進行了系統時間的修改操作,包括系統自動同步網絡時間,都有可能導致這個Timer任務掛起。
系統時間修改到當前時間之后,不會影響Timer的執行;但是如果系統時間修改到當前時間之前,就會導致Timer掛起。詳見博文:“關于Timer運行時修改系統時間”。
要解決這個問題的話,需要程序在系統時間改變之后主動重啟Timer,Android系統在系統時間被修改之后,會發出一條廣播:Intent.ACTION_TIME_CHANGED,我們只需要監聽這個廣播即可。
在onCreate方法或者其它合適的地方注冊廣播監聽方法:
IntentFilter?filter?=?new?IntentFilter();
filter.addAction(Intent.ACTION_TIME_CHANGED);
filter.addAction(Intent.ACTION_DATE_CHANGED);
this.registerReceiver(new?TimeChangedReceiver(),?filter);
然后實現廣播監聽器:
public?class?TimeChangedReceiver?extends?BroadcastReceiver?{
@Override
public?void?onReceive(Context?context,?Intent?intent)?{
Log.d(TAG,?"---onReceive()?start!---");
String?action?=?intent.getAction();
if?(Intent.ACTION_DATE_CHANGED.equals(action))?{
Log.d(TAG,?"---DATE_CHANGED!---");
}
if?(Intent.ACTION_TIME_CHANGED.equals(action))?{
mHandlerMsg.sendEmptyMessage(MsgType.RESTARTTIMER);
Log.d(TAG,?"---TIME_CHANGED!---");
}
Log.d(TAG,?"---onReceive()?end!---");
}
}
具體的Timer重啟方法放在了Handle中:
final?static?class?MsgType?{
...
final?static?int?RESTARTTIMER?=?7;
...
}
final?Handler?mHandlerMsg?=?new?Handler(new?Handler.Callback()?{
...
@Override
public?boolean?handleMessage(Message?msg)?{
switch?(msg.what)?{
...
case?MsgType.RESTARTTIMER:?{
try?{
timer.cancel();
}?catch?(Exception?e)?{
e.printStackTrace();
}
timer?=?null;
timer?=?new?Timer();
timer.schedule(new?firstTask(),?0,?TIMER_INTERVAL);
}
break;
...
}
}
...
}
firstTask代碼如下:
class?firstTask?extends?TimerTask?{
@Override
public?void?run()?{
//?TODO?do?something
}
}
通過以上這種方式就可以解決在修改了系統時間后Timer被掛起的問題。