谷歌在今年的Google I/O
上宣布了一项非常令人兴奋的功能,该功能允许开发人员执行传统上需要详细了解各种API级别和可用于这些API的后台任务库的后台任务(简单点说就是”管理一些要在后台工作的任务, – 即使你的应用没启动也能保证任务能被执行”),这就是WorkManager,WorkManager
提供了从其他API
(例如JobScheduler
,Firebase.JobDispatcher
,AlarmManager
和Services
)中获得的功能,而无需研究哪种API
可用于您的设备或API
。
这句话是什么意思?既然能用JobScheduler
和AlarmManager
等,何必再出来个WorkManager
呢?其实WorkManager
在底层也是看你是什么版本来选到底是JobScheduler
,AlamarManager
来做。
JobScheduler
是在SDK
21中才有的,而且在SDK
21中还有Bug
,稳定可用是从SDK
23开始的. 而AlarmManager
一直存在,但是AlarmManager
也不是最好的选择,
注意:如果您的应用程序的目标是API
级别26或更高,则当应用程序本身不在前台时,系统会对运行后台服务施加限制。在大多数情况下,您的应用程序应该使用预定作业。所以WorkManager
在底层, 会根据你的设备情况, 选用JobScheduler
,Firebase
的JobDispatcher
,或是AlarmManager
。
WorkManager
,它在应用被杀, 甚至设备重启后仍能保证你安排给他的任务能得到执行。那这样我们以后是不是可以把后台任务都用它来实现了?其实Google
自己也说了:WorkManager
并不是为了那种在应用内的后台线程而设计出来的. 这种需求你应该使用ThreadPool
。
具体的规则如下:
WorkManager
根据以下标准在可用时使用对应的底层工作服务:
- 在
API 23+
使用JobScheduler
- 在
API 14-22
中- 如果在应用中使用了
Firebase JobDispatcher
并且有可选的Firebase
依赖项就使用Firebase JobDispatcher
- 否则使用自定义的
AlarmManager + BroadcastReceiver
的实现方式
- 如果在应用中使用了
组成部分:
WorkManager
:通过对应的参数来接受work
并排队执行work
。Worker
:通过实现doWork()
方法来指定在后台执行的具体功能。WorkRequest
:代表一个独立的任务。它会告诉你哪个worker
加入了,以及它需要满足哪些约束才能运行。WorkRequest
是一个抽象类,您将使用OneTimeWorkRequest或PeriodicWorkRequest。WorkStatus
:为每个WorkRequest对象提供数据。
好了下面开始演示:
首先加入依赖:
dependencies {
def work_version = "1.0.0-alpha02"
implementation "android.arch.work:work-runtime:$work_version"
}
- 继承
Worker
类并实现doWork()
方法
class MineWorker : Worker() {
override fun doWork(): WorkerResult {
Log.e("@@@", "dang dang dang !!!")
return WorkerResult.SUCCESS
}
}
- 接下来如果想要该
Worker
执行,需要调用WorkManager
将该Worker
添加到队列中
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val workRequest = OneTimeWorkRequest.Builder(MineWorker::class.java).build()
val instance = WorkManager.getInstance()
instance.enqueue(workRequest)
}
}
好了,执行下:
05-29 12:15:51.066 6360-6406/com.charon.workmanagerdemo E/@@@: dang dang dang !!!
并没什么卵用,因为这个示例代码就上来就执行一次。 很显然这个不合理啊,我想给该worker
添加一些限制条件,例如我想在手机充电时,并且有网的情况下执行某个任务,
而且我想让它执行多次,这里可以通过Constraints
来限制:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.setRequiresCharging(true)
.build()
val workRequest = OneTimeWorkRequest.Builder(MineWorker::class.java)
.setConstraints(constraints).build()
val instance = WorkManager.getInstance()
instance.enqueue(workRequest)
}
我们把手机网络关掉运行下,这次运行后并没有log
打印。那现在把网络打开:
05-29 12:21:02.061 7092-7241/? E/@@@: dang dang dang !!!
当然我们可以获取每个请求的状态,以及取消该请求:
val statusById: LiveData<WorkStatus> = instance.getStatusById(workRequest.id)
instance.cancelWorkById(workRequest.id)
如果想要顺序的去执行不同的OneTimeWorker
也是很方便的:
WorkContinuation chain1 = WorkManager.getInstance()
.beginWith(workA)
.then(workB);
WorkContinuation chain2 = WorkManager.getInstance()
.beginWith(workC)
.then(workD);
WorkContinuation chain3 = WorkContinuation
.combine(chain1, chain2)
.then(workE);
chain3.enqueue();
上面都是用了OneTimeWorkRequest
,如果你想定期的去执行某一个worker
的话,可以使用PeriodicWorkRequest
:
val workRequest = PeriodicWorkRequest.Builder(MineWorker::class.java, 3, TimeUnit.SECONDS)
.setConstraints(constraints)
.setInputData(data)
.build()
但是我使用这个定期任务执行的时候也只是执行了一次,并没有像上面的代码中那样3秒执行一次,什么鬼?
我们看看PeriodicWorkRequest
的源码:
/**
* A class that represents a request for repeating work.
*/
public final class PeriodicWorkRequest extends WorkRequest {
/**
* The minimum interval duration for {@link PeriodicWorkRequest}, in milliseconds.
* Based on {@see https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/app/job/JobInfo.java#110}.
*/
public static final long MIN_PERIODIC_INTERVAL_MILLIS = 15 * 60 * 1000L; // 15 minutes.
上面说的很明白,最小间隔15分钟,- -!
总体来说,WorkManager
并不是要取代线程池AsyncTask/RxJava
.反而是像AlarmManager
来做定时任务的意思.即保证你给它的任务能完成, 即使你的应用都没有被打开, 或是设备重启后也能让你的任务被执行.WorkManager
在设计上设计得比较好.没有把worker
,任务混为一谈,而是把它们解耦成Worker
,WorkRequest
.这样分层就清晰多了, 也好扩展.
到了这里突然有了一个大胆的想法。看到没有它能保证任务的执行。
我们之前写过一篇文章Android卸载反馈
里面用到了c
中的fork
来保证存活,达到常驻内存的功能,如果PeriodicWorkRequest
的最小间隔时间比较短不是15分钟的话,那这里是不是也可以用WorkManager
来实现? 好了,不说了。
参考:
- 邮箱 :charon.chui@gmail.com
- Good Luck!