一、JobScheduler 到底是什么?

说实话,我刚接触 Android 开发那会儿,对 JobScheduler 的第一印象就是——「又一个系统调度工具」。但用久了才发现,这玩意儿其实是 Google 给开发者挖的一口「良心井」。

JobScheduler 是 Android 5.0(API 21)引入的一套任务调度框架。它的核心思想很简单:把任务交给系统,让系统决定什么时候执行

你可能会问:「我自己开个线程跑不行吗?」行,但代价很大。我见过太多应用因为后台任务写得糙,被系统一刀切掉。嗯,JobScheduler 就是来解决这个问题的。

1.1 它解决了什么问题?

说白了,JobScheduler 要解决三个核心痛点:

  • 省电:系统会把多个 App 的任务合并到一起执行,减少 CPU 唤醒次数
  • 避免滥用后台:防止 App 在后台偷偷跑任务,耗电又占内存
  • 适配 Doze 模式:Android 6.0 开始,设备休眠后网络和 CPU 都会被限制,普通 Service 根本跑不起来

我记得有个项目,用户反馈「手机放一晚上,电量掉了 30%」。查了半天,发现是某个第三方 SDK 在后台疯狂轮询。换成 JobScheduler 后,电量消耗直接降到了 5% 以内。

1.2 核心工作流程

先看一张图,帮你快速理解 JobScheduler 的运作逻辑:

JobScheduler 核心工作流程 App 提交 Job JobInfo.Builder JobScheduler Service 系统级调度服务 条件满足? 网络/充电/空闲 否,等待 执行 JobService onStartJob() 回调 任务完成 / 重试

流程其实不复杂:你提交一个 Job,告诉系统「我想在充电且连 WiFi 的时候干某件事」。系统会把这些请求攒起来,等到条件满足时统一执行。

二、和 Service、AlarmManager 的对比

很多新手会问:「我有 Service 和 AlarmManager 就够了,为什么还要学 JobScheduler?」

这个问题我当年也问过。来,直接看对比表:

特性 JobScheduler Service AlarmManager
触发条件 网络、充电、空闲等组合条件 手动启动 / 绑定 指定时间 / 间隔
省电策略 系统统一调度,批量执行 无,常驻后台 可唤醒设备,耗电较高
Doze 兼容 原生支持,自动适配 Doze 下会被杀死 需特殊处理
保活能力 任务完成后自动结束 可长期运行 触发后执行短暂操作
适用场景 后台同步、日志上传、预加载 音乐播放、位置追踪 闹钟、定时提醒

2.1 为什么 Service 不适合做延迟任务?

你想想看,Service 一旦启动,只要你不调 stopSelf(),它就会一直活着。这在 Doze 模式下是致命的——系统会直接把你整个进程杀掉。

我曾经接手过一个项目,里面用 Service 做每 5 分钟一次的数据上报。结果呢?Android 8.0 以后,后台 Service 直接被限制,那个功能彻底废了。后来改成 JobScheduler,问题才解决。

2.2 AlarmManager 的局限性

AlarmManager 适合做「到点就干」的事,比如闹钟。但它有个问题:它只管时间,不管其他条件。

举个例子:你想在「连上 WiFi 且手机空闲」的时候下载一个大文件。用 AlarmManager 你只能设个时间,但到了时间如果没 WiFi,任务还是会触发,然后失败。JobScheduler 就不会——它会等到条件全部满足再执行。

核心结论: Service 管「活着」,AlarmManager 管「准时」,JobScheduler 管「聪明地干活」。

三、一个最简单的例子

光说不练假把式。来看一段最基础的 JobScheduler 用法:

// 1. 构建 JobInfo
JobInfo jobInfo = new JobInfo.Builder(
    JOB_ID, 
    new ComponentName(context, MyJobService.class)
)
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED) // 仅 WiFi
.setRequiresCharging(true) // 仅充电时
.setPeriodic(15 * 60 * 1000) // 每 15 分钟执行一次
.build();

// 2. 提交给系统
JobScheduler scheduler = 
    (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
scheduler.schedule(jobInfo);

// 3. 定义 JobService
public class MyJobService extends JobService {
    @Override
    public boolean onStartJob(JobParameters params) {
        // 在这里执行你的后台任务
        // 返回 true 表示任务还在执行,系统会等你调 jobFinished()
        new Thread(() -> {
            doBackgroundWork();
            jobFinished(params, false); // 任务完成,false 表示不需要重试
        }).start();
        return true;
    }

    @Override
    public boolean onStopJob(JobParameters params) {
        // 系统强制停止任务时回调
        // 返回 true 表示希望重试
        return true;
    }
}
个人习惯: 我一般会在 onStartJob 里返回 true,然后在新线程里做耗时操作。这样即使主线程卡了,系统也不会误判任务已经结束。

四、什么时候该用 JobScheduler?

根据我的经验,下面这些场景用 JobScheduler 最合适:

  • 数据同步:比如新闻 App 在 WiFi 下预加载文章
  • 日志上传:等用户充电且连 WiFi 时上传崩溃日志
  • 缓存清理:设备空闲时清理过期缓存
  • 预下载:预测用户可能要看的内容,提前下载
注意: JobScheduler 不适合做「必须准时执行」的任务。比如闹钟、倒计时提醒,这些还是得用 AlarmManager。我曾经有个同事非要用 JobScheduler 做闹钟,结果用户投诉闹钟晚了半小时才响——因为系统在等「空闲条件」。

五、小结

JobScheduler 说白了就是 Google 给开发者的一把「省电利器」。它把任务调度的主动权交给了系统,让系统根据当前电量、网络、设备状态来合理安排执行时机。

和 Service 比,它更省电;和 AlarmManager 比,它更智能。但也不是万能的——关键看你用对场景没有。

嗯,这一章先带你入个门。后面我们会深入源码,看看 JobScheduler 到底是怎么调度任务的,以及如何写出更高效的 Job。


公众号:蓝海资料掘金营,微信deep3321