Skip to content

实现定时循环

方法1:Handler + postDelayed

使用 HandlerpostDelay(Runnable, delayMillis) 方法实现定时任务。 该方法适用于需要在主线程或其他线程中处理短时间间隔任务的场景,例如更新UI轻量级任务

代码示例

java
Handler handler = new Handler(Looper.getMainLooper());
Runnable runnable = new Runnable() {
  @Override
  public void run() {
    Log.d("HandlerExample", "定时任务");
    handler.postDelayed(this, 1000);
  }
}

// 开启定时任务
handler.postDelayed(runnable, 1000);

// 停止定时任务
handler.removeCallback(runnable);

优点

  • 简单易用,适合短时间延迟任务。
  • 与Looper紧密结合,能跟线程生命周期绑定。
  • 在主线程运行时,不用担心线程安全问题。

缺点

  • 需要手动管理任务的取消,避免内存泄漏。
  • 不适合高频或者精确的任务调度。
  • 依赖线程的生命周期,线程结束后任务就会被清除。
  • 主线程过载时可能会导致任务延迟。

方法2:AlarmManager

使用 AlarmManagersetRepeating 方法。 适用场景:需要在设备休眠时唤醒设备并执行任务的场景。例如,定时提醒,后台定时同步任务。

优点

  • 即便设备进入休眠模式,也能触发任务。
  • 节能高效,适合低频任务。
  • 能指定触发时间的精度。

缺点

  • 适合较低频率的任务,间隔时间太短会影响性能。
  • 会受到 Doze 模式的限制。

代码示例

java
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, MyBroadcastReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);

long triggerAtMillis = SystemClock.elapsedRealtime() + 60000; // 1分钟后触发
long intervalMillis = 60 * 1000;
// 设置重复性报警
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    // 对于 API 23 及以上,使用 setAndAllowWhileIdle 或 setExactAndAllowWhileIdle
    // 注意: setRepeating 不支持高精度定时
    alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtMillis, intervalMillis, pendingIntent);
} else {
    // 对于较低版本的 Android,直接使用 setRepeating
    alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtMillis, intervalMillis, pendingIntent);
}

方法3:JobScheduler

使用 JobScheduler 调度任务,通过 JobInfo 配置定时条件。 适用于后台定时任务,如定期上传日志清除缓存等。

优点

  • 与系统资源管理紧密结合,任务调度智能
  • 节能高效,可以根据网络、充电状态等条件执行任务
  • 系统会自动处理任务的重复和恢复

缺点

  • 配置复杂性高
  • 精确度较低,依赖系统的调度优化

代码示例

java
import android.app.job.JobParameters;
import android.app.job.JobService;
import android.util.Log;

public class MyJobService extends JobService {

    private static final String TAG = "MyJobService";

    @Override
    public boolean onStartJob(JobParameters params) {
        // 执行任务的代码
        Log.i(TAG, "Job started!");
        
        // 执行定时任务后,重新安排任务,创建新的 JobInfo
        scheduleJob();
        
        // 返回 true 表示任务正在执行,系统需要等待任务完成
        return true;
    }

    @Override
    public boolean onStopJob(JobParameters params) {
        // 任务被取消时调用
        Log.i(TAG, "Job stopped!");
        return false; // 表示不需要重试
    }

    // 设置 JobScheduler 循环定时任务
    private void scheduleJob() {
        JobScheduler jobScheduler = (JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE);
        
        // 创建一个周期性任务
        JobInfo jobInfo = new JobInfo.Builder(123, new ComponentName(this, MyJobService.class))
                .setPeriodic(60 * 1000)  // 设置任务周期为 60 秒
                .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) // 需要网络连接
                .setPersisted(true) // 设置任务重启后继续执行
                .build();

        // 调度任务
        if (jobScheduler != null) {
            jobScheduler.schedule(jobInfo);
        }
    }
}

方法4:WorkManager

使用 workManager 配置定时任务,通过 PeriodicWorkRequest 设置任务的重复间隔。 适用于需要可靠、定时执行的任务,且不依赖高精度定时的场景,如定期同步数据上传文件

优点

  • 高可靠性:即使设备重启也能恢复任务。
  • 简单易用:api调用方便
  • 支持约束条件,如网络状态、电池电量等。

缺点

  • 精度比较低,最小间隔15分钟(适用于非实时任务)。
  • 配置和依赖比较复杂。
java
PeriodicWorkRequest workRequest = new PeriodicWorkRequest.Builder(MyWorker.class, 15, TimeUnit.MINUTES).build();
WorkManager.getInstance(context).enqueue(workRequest);

// 自定义Worker
public class MyWorker extends Worker {
    public MyWorker(Context context, WorkerParameters workerParams) {
        super(context, workerParams);
    }

    @NonNull
    @Override
    public Result doWork() {
        Log.d("WorkManager", "后台任务执行");
        return Result.success();
    }
}

方法5:Timer + TimeTask

使用 TimerTimerTask 实现定时循环 适用于简单的短期非定时任务,例如执行少量后台操作。

优点

  • 使用简单,适合快速开发
  • 可灵活指定延迟和周期

缺点

  • 与线程绑定,线程结束后任务会被中断。
  • 不推荐在安卓项目中使用,有潜在的问题。
java
Timer timer = new Timer();
TimerTask timerTask = new TimerTask(){
  @override
  public void run(){
    Log.d("timerTask", "任务运行中")
  }
}

// 每3秒执行一次
timer.scheduleAtFixedRate(timerTask, 0, 3000);

// 停止任务
timer.cancel();

方法6:HandlerThread + Handler

在 HandlerThread 中运行 Handler 定时调度任务。 适用于需要在后台线程中定时处理轻量级任务的场景。

优点

  • 线程独立,任务与UI无关
  • 不会阻塞主线程

缺点

  • 需要手动管理线程生命周期
  • 不够现代化
java
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.util.Log;

public class HandlerThreadExample {

    private static final String TAG = "HandlerThreadExample";
    private HandlerThread handlerThread;
    private Handler backgroundHandler;

    public void start() {
        // 创建一个 HandlerThread
        handlerThread = new HandlerThread("BackgroundThread");
        handlerThread.start();

        // 创建一个与 HandlerThread 相关联的 Handler
        Looper looper = handlerThread.getLooper();
        backgroundHandler = new Handler(looper) {
            @Override
            public void handleMessage(Message msg) {
                // 处理消息
                switch (msg.what) {
                    case 1:
                        Log.i(TAG, "定时任务执行");
                        break;
                    default:
                        super.handleMessage(msg);
                }
                // 设置定时任务,发送下一个任务
                backgroundHandler.sendEmptyMessageDelayed(1, 1000); // 1秒后再次执行
            }
        };

        // 启动第一次定时任务
        backgroundHandler.sendEmptyMessage(1);
    }

    public void stop() {
        // 退出线程
        if (handlerThread != null) {
            handlerThread.quit();
        }
    }

    public static void main(String[] args) {
        HandlerThreadExample example = new HandlerThreadExample();
        example.start();

        // 为了演示,主线程等待一段时间,观察输出
        try {
            Thread.sleep(10000); // 主线程等待10秒,观察输出
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 停止定时任务
        example.stop();
    }
}

方法7:CountDownTimer

使用 CountDownTimer 提供的回调方法,执行倒计时逻辑。 适用于倒计时场景,如倒计时按钮、限时操作提示。

优点

  • 易于实现倒计时功能。
  • 提供精确的时间控制。

缺点

  • 无法直接实现重复循环任务
  • 不适合复杂任务调度
java
CountDownTimer countDownTimer = new CountDownTimer(10000, 1000) {
    @Override
    public void onTick(long millisUntilFinished) {
        Log.d("CountDownTimer", "剩余时间: " + millisUntilFinished / 1000);
    }

    @Override
    public void onFinish() {
        Log.d("CountDownTimer", "倒计时结束");
    }
};

countDownTimer.start();

方法8:ScheduledExecutorService

使用Java的 ScheduledExecutorService 提供的 scheduleAtFixedRateschedulewithFixedDelay 方法。 适用于后台线程中高精度的定时任务,例如网络轮询性能监控

优点

  • 精确的时间调度
  • 线程池管理,支持并发

缺点

  • 不会考虑Android系统的资源管理
  • 手动处理线程生命周期和任务取消
java
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
Runnable task = new Runnable() {
    @Override
    public void run() {
        Log.d("ScheduledExecutor", "后台定时任务");
    }
};

// 每隔2秒执行一次任务
executor.scheduleAtFixedRate(task, 0, 2, TimeUnit.SECONDS);

// 关闭任务
// executor.shutdown();

方法9:RxJava + Interval/Timer

使用 RxJavaObservable.IntervalObservable.timer 方法创建定时流。 适用于响应式编程场景,实时数据刷新事件轮询

优点

  • 代码简洁,与响应式编程风格一致。
  • 可以轻松组合和转换数据流

缺点

  • 容易导致内存泄漏,需要注意订阅管理。
java
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.schedulers.Schedulers;

public class RxJavaIntervalExample {

    public static void main(String[] args) {
        Observable.interval(1, TimeUnit.SECONDS) // 每秒发射一次
                .observeOn(Schedulers.io()) // 在后台线程执行
                .subscribe(time -> {
                    System.out.println("定时任务执行: " + time + "秒");
                });

        // 为了演示,主线程等待一段时间
        try {
            Thread.sleep(10000); // 让主线程等待10秒,观察输出
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

方法10:kotlin Coroutine + delay

使用 Kotlin 的 delay 实现定时器 适用于安卓开发中轻量级异步定时任务。

优点:

  • 非阻塞,性能强
  • 协程整合良好
java
import kotlinx.coroutines.*

fun main() = runBlocking {
    val job = launch {
        while (isActive) {
            println("Coroutine working...")
            delay(1000) // 每秒执行一次
        }
    }

    delay(5000) // 5秒后取消任务
    job.cancelAndJoin()
}

总结对比

方法精度适用场景系统节能易用性备注
Handler + postDelayed短时间任务简单任务最佳选择
AlarmManager唤醒设备的低频任务系统资源占用低
JobScheduler后台任务,考虑约束条件适合后台管理任务
WorkManager后台可靠任务,系统推荐最现代化的选择
Timer + TimerTask轻量循环任务不推荐,过时
HandlerThread + Handler线程独立的定时任务传统方式之一
CountDownTimer倒计时功能简单高效倒计时
ScheduledExecutorService精确后台任务调度高性能需求适用
RxJava + Interval/Timer响应式编程场景现代化需求适用
Kotlin Coroutines + delay异步轻量任务现代开发优先

Released under the MIT License.