Service 執行緒拋出未捕獲異常導致進程崩潰,系統依 onStartCommand 回傳值決定是否重啟。回傳 START_STICKY 可讓系統在記憶體允許時重建 Service 並呼叫 onStartCommand(null, 0, 0)。
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// 初始化工作...
return START_STICKY; // 關鍵:告訴系統崩潰後重啟
}
public class UpdateService extends Service {
private Timer timer;
private static final long INTERVAL = 60_000;
@Override
public void onCreate() {
super.onCreate();
startPolling();
}
private void startPolling() {
timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
try {
// 網路請求、資料庫操作等風險工作
doWork();
} catch (Exception e) {
Log.e("UpdateService", "Polling error", e);
// 關鍵:捕獲異常防止執行緒死亡
// 若想觸發系統重啟,可拋出 RuntimeException
// throw new RuntimeException(e);
}
}
}, 0, INTERVAL);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
if (timer != null) {
timer.cancel();
timer = null;
}
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
| 常數 | 重啟行為 | Intent 遞送 | 適用場景 |
|---|---|---|---|
| START_STICKY | 是 | onStartCommand(null, 0, 0) | 長期運行、狀態可自行恢復的服務(音樂播放、定時同步) |
| START_NOT_STICKY | 否 | 無 | 一次性工作、由呼叫端控制生命週期 |
| START_REDELIVER_INTENT | 是 | 重傳最後 Intent | 需保證完成的關鍵任務(上傳、下載) |
// 方案一:執行緒層級捕獲(推薦)
Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {
Log.e("Service", "Uncaught exception in " + thread.getName(), throwable);
// 可選:上報崩潰分析平台
});
// 方案二:TimerTask 內部 try-catch(如上例)
// 方案三:ExecutorService + Future.get() 捕獲
START_STICKY 更穩健。
設定 START_STICKY 並妥善捕獲執行緒異常,即能讓 Service 在異常崩潰後自動復原,保障長期任務連續性。