Android Service:Timer任务等待BroadcastReceiver响应的问题及优化
As someone new to Android development, my initial implementation using Timer worked most of the time but had occasional odd behavior. Here's the stripped-down version of my first attempt:
private Timer timer; private TimerTask timerTask; public void startTimer() { timer = new Timer(); initializeTimerTask(); timer.schedule(timerTask, 10000, 10000); } public void initializeTimerTask() { timerTask = new TimerTask() { public void run() { runSendJob(jsonData, SentReceiver); // Wait up to 10 seconds for broadcast receiver response long startTime = System.currentTimeMillis(); while(bResult.equals(false) && (System.currentTimeMillis()-startTime)<10000){ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } if (bResult.equals(true)){ UpdateLog(); } } } }; }
The Problem
When runSendJob plus the wait for the BroadcastReceiver response took 10-20 seconds total, the Timer would trigger the next task immediately after the current one finished—completely ignoring the intended 10-second interval.
The Fix: Switching to ScheduledExecutorService
I redesigned the implementation using ScheduledExecutorService, which handles task scheduling more reliably for long-running operations. Here's the updated code:
public class MyService extends Service { BroadcastReceiver SentReceiver; public Boolean bResult; private Handler mHandler; private ScheduledExecutorService mExecutor; // Define delays as constants for clarity private static final long DELAY_0 = 0; private static final long DELAY_10 = 10; private static final TimeUnit DELAY_SECONDS = TimeUnit.SECONDS; @Override public void onCreate() { super.onCreate(); mHandler = new Handler(); commandStart(); } private void commandStart() { if (mExecutor == null) { mExecutor = Executors.newSingleThreadScheduledExecutor(); Runnable runnable = new Runnable() { @Override public void run() { startMyTask(); } }; // Schedule with fixed delay: waits DELAY_10 seconds after the previous task ends mExecutor.scheduleWithFixedDelay(runnable, DELAY_0, DELAY_10, DELAY_SECONDS); Log.d(TAG, "commandStart: starting executor"); } else { Log.d(TAG, "commandStart: do nothing"); } SentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context arg0, Intent arg1) { switch(getResultCode()) { case Activity.RESULT_OK: bResult = true; break; case Activity.RESULT_CANCELED: bResult = false; break; } } }; registerReceiver(SentReceiver, new IntentFilter("MSG_SENT")); } public void startMyTask() { runSendJob(jsonData, SentReceiver); // Wait up to 10 seconds for broadcast receiver response long startTime = System.currentTimeMillis(); while(bResult.equals(false) && (System.currentTimeMillis()-startTime)<10000){ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } if (bResult.equals(true)){ UpdateLog(); } // Spin off other jobs if needed mHandler.post(new Runnable() { @Override public void run() { updateSomethingElse(); } }); } } }
Why This Works
scheduleWithFixedDelay ensures that each task starts only after the previous one has completed plus the specified delay. Unlike Timer.schedule, which schedules based on the start time of the previous task, this matches my requirement of maintaining a consistent 10-second gap between the end of one task and the start of the next.
Since making this change, the service runs reliably with a steady 10-second interval between tasks.
内容的提问来源于stack exchange,提问作者Emsg

