一看标题,使用定时器,学Java基础就有,使用Timer类啊,不是这样的。
比如,条件时,在充电时、网络时、低电量时、低存储时、手机空闲时等等,我们需要在这些其中的一个或多个条件满足后的某个时间内才执行的一些任务,要怎么实现?
早期用:AlarmManager + BroadcastReceiver
后来用:JobScheduler
现在:WorkManager
注:WorkManager不是用来处理所有后台任务的,什么样的后台任务用什么API,官方文档在此。
使用早期的方式比较麻烦,后来就有了JobScheduler,但是JobScheduler是Api 21才出来的,有兼容性问题,所以后来有了WorkManager,可以兼容到Android4.0版本。
我是发现公司的一个项目上使用到了JobScheduler开始学习的,学懂一点点没多久就发现又有了WorkManager,罪过,学Android咋这么苦啊,东西多的学不过来,这篇文章只能记录下一些文章连接了,没这么多时间了现在,工作上又好多东西要做的,只能先记录一下了。
这儿有一篇好文章:https://segmentfault.com/a/1190000006101221
官方,后台任务处理:https://developer.android.com/guide/background#ap
官方推荐的4种最佳后台工作方式:
WorkManager
前台服务
AlarmManager
DownloadManager
2019年11月19日官方博客:在Android上统一后台任务计划
WorkManager一个重要的说明:
WorkManager用于可延迟的工作(即,不需要立即运行),并且即使应用程序退出或设备重新启动也需要可靠地运行。例如:
- 将日志或分析发送到后端服务
- 定期将应用程序数据与服务器同步
WorkManager不适用于进行中的后台工作,如果应用程序进程消失,该后台工作可以安全终止,或者用于需要立即执行的工作。请查看[后台处理指南]( ),以了解哪种解决方案可以满足您的需求。
==============================================================================
已经过时了,但是今天学了一点,过时归过时,还是记录一下吧。
定时执行一些任务,任务一般是耗时的吧,所以要用Service,定义一个类继承JobService,如下:
class MyJobService: JobService() {
override fun onStartJob(params: JobParameters?): Boolean {
// 当条件满足时就会执行这里的代码,比如有网络的情况下,5秒后执行这里,如果5秒内又没网了,则不会执行。如果等到有网了之后会立即执行(已经过了最短),不会再重新计算5秒。
Log.i(TAG, "${getCurrentTime()}:onStartJob")
return true
}
override fun onStopJob(params: JobParameters?): Boolean {
Log.i(TAG, "${getCurrentTime()}:onStopJob")
return true
}
companion object {
fun getCurrentTime() = DateFormat.format("kk:mm:ss", System.currentTimeMillis())
}
}
在onStartJob方法中执行自己的具体任务逻辑,需要开子线,因为Service是运行在主线程的,而这个Service什么时候执行呢?就需要使用到JobScheduler,它就可以定义需要满足什么条件,延迟多久执行任务等一些条件设置,代码如下:
class MyJobService: JobService() {
companion object {
val TAG: String = "MyJobService"
var jobScheduler: JobScheduler? = null
fun getCurrentTime() = DateFormat.format("kk:mm:ss", System.currentTimeMillis())
fun startScheduler(context: Context) {
jobScheduler = context.getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler
// 注:JobInfo可以声明为成员变量,只创建一次,在重复执行任务时可以复用。
val job: JobInfo = JobInfo.Builder(1, ComponentName(context, MyJobService::class.java))
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
// 指定任务的延迟时间,即5秒后才开始此任务,即调用了jobScheduler.schedule()方法之后等5秒后再执行任务,任务就是判断如果有网络,则执行JobService的onStartJob方法
// 如果5秒后任务条件没有满足,等到满足的时候就会立马执行JobService的onStartJob方法
.setMinimumLatency(TimeUnit.SECONDS.toMillis(5)) // 最小为5秒,设置更小将使用5秒
//.setOverrideDeadline(TimeUnit.SECONDS.toMillis(10)) // 设置最大延迟时间为10秒,则调用jobScheduler.schedule()方法之后如果10秒后条件还不满足也执行JobService的onStartJob方法
// .setPeriodic(TimeUnit.SECONDS.toMillis(3)) // 最小间隔为15分钟(定义在JobInfo.getMinPeriodMillis()),不能比这个小,如果比这个小估计就会使用15分钟
.build()
val result = jobScheduler?.schedule(job)
Log.i(TAG, "${getCurrentTime()}:startScheldur:${if (result == 0) "RESULT_FAILURE" else "RESULT_SUCCESS"}")
}
fun cancelScheldur() {
jobScheduler?.cancelAll()
}
}
}
这里设置了条件,5秒后执行任务,任务的条件是有网络才执行MyJobService中的onStartJob方法。
关于onStartJob方法:JobParameters参数,由系统创建,如果想放里面存放一些内容,在JobInfo.Builder中可以设置。方法返回值,true代表任务还在执行,当自己的任务执行完成后调用jobFinished来告诉系统,此时系统会释放唤醒锁,不知道这个锁是什么东西。如果返回false,表示任务结束,系统直接释放唤醒锁。
onStopJob方法,并不是说任务结束了就会调用此方法,比如调用了jobFinished后此方法也不会执行。此方法执行的话,表示之前条件已经满足了,onStartJob方法已经执行了,但是此方法返回true,而且没有调用jobFinished,则系统并没有释放唤醒锁,如果此时条件突然不满足了则会回调此方法,比如你需要有网络才执行一个下载任务,当有网络时onStartJob开始执行,然后突然网络断开,则onStopJob开始执行,意思就是告诉你,网络没有了,你快停止下载任务吧,而且此时系统会释放唤醒锁,又或者你还没下载完,我们调用了jobScheduler.cancelAll()方法,表示取消任务,则onStopJob会执行,总之,onStopJob执行时,肯定是已经执行过了onStartJob的,onStopJob执行是告诉你条件突然不满足了,快停止你正在进行的任务。如果在onStartJob调用后,当你的任务完成时,你应该调用jobFinished方法来告诉系统你的任务完成了,此时系统释放唤醒锁,如果此时突然条件不满足了,系统也不会调用onStopJob了,因为你的任务已经完成了,即使你没完成,但是你调用了jobFinished就表示已经完成了,所以系统就没必要调用onStopJob来通知你停止任务了。 返回值:false表示工作完全结束,true表示你的工作没有结束,但你也必须停止你的任务,系统会根据你创建任务时提供的重试条件重新安排任务,即在下次条件满足时再来执行你的任务。再细说一下返回true的细节,如果d onStartJob中返回true,onStopJob中也返回true,则当条件满足后执行onStartJob,此后当条件不满足时执行onStopJob,如果设置了重试,则当条件再次满足时会再执行onStartJob,然后条件不满足时又执行onStopJob,即如果我们不调用jobFinished方法,在条件满足和不满足时就会一直执行onStartJob和onStopJob方法,实现只要条件一达到就执行一次任务。而如果onStopJob返回false,则只要onStopJob被调用一次,则表示任务已经结束了,之后 条件满足也不再执行onStartJob。 重试是通过JobInfo.Builder的setBackoffCriteria(long initialBackoffMillis, @BackoffPolicy int backoffPolicy)方法进行设置,第一个参数是设置延迟多少时间后再开始任务,开始任务不是说立马执行onStartJob,而是说指定的延迟时间之后 ,如果条件满足了则立即执行onStartJob,如果不满足则等到满足了才会执行onStartJob,第二参数是一个策略,如果指定为线性,假如延迟时间为10秒,则第一次重试延迟10秒,第二次重试时延迟20秒,第三次延迟30秒。。。
总结就是:一般onStartJob和onStopJob都返回true,在onStartJob中完成任务时再调用jobFinished,这样的话,在任务没完成时如果条件突然不满足了,则任务肯定要暂停了,则我们可以通过重试策略在将来条件再次满足时再继续我们的任务。
学完这些知识点就可以做这样一个需求了,完成一个类似定时器的功能,每5秒钟执行一次,而且是有网络的情况下才执行,如果没有网络就等到有网络才执行(如果实现定时向服务器发送心跳包),代码如下:
class MyJobService: JobService() {
override fun onStartJob(params: JobParameters?): Boolean {
Log.i(TAG, "${getCurrentTime()}:onStartJob")
startScheduler(this)
return false
}
override fun onStopJob(params: JobParameters?) = false
companion object {
val TAG: String = "MyJobService"
var jobScheduler: JobScheduler? = null
var job: JobInfo? = null
### 总结
最后为了帮助大家深刻理解Android相关知识点的原理以及面试相关知识,这里放上相关的我搜集整理的24套**腾讯、字节跳动、阿里、百度2019-2021面试真题解析**,我把技术点整理成了**视频和PDF**(实际上比预期多花了不少精力),包**知识脉络 + 诸多细节**。
还有 **高级架构技术进阶脑图、Android开发面试专题资料** 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。



网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。
> 2021年虽然路途坎坷,都在说Android要没落,但是,不要慌,做自己的计划,学自己的习,竞争无处不在,每个行业都是如此。相信自己,没有做不到的,只有想不到的。祝大家2021年万事大吉。
[外链图片转存中...(img-B71UilCK-1718773754076)]
[外链图片转存中...(img-eFCtpwMI-1718773754077)]
网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。
> 2021年虽然路途坎坷,都在说Android要没落,但是,不要慌,做自己的计划,学自己的习,竞争无处不在,每个行业都是如此。相信自己,没有做不到的,只有想不到的。祝大家2021年万事大吉。