使用案例
使用分为三步骤
1.创建自定义worker,处理后台任务
2.利用建造者模式 构建WorkRequest(抽象类) 请求,有两个实现类
OneTimeWorkRequest单次执行任务,执行一次就结束了
PeriodicWorkRequest 多次循环执行任务
构建请求的时候,还可以添加约束条件setConstraints(@NonNull Constraints constraints)
3.WorkManager 把请求加入队列
自定义worker--简单案例
class MainWork1(val context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) {
//后台任务,并且是 异步放入,线程池执行runnable
override fun doWork(): Result {
Log.d("hh", "mainWork1 doWork:run starting...")
//Toast.makeText(context,"start",Toast.LENGTH_SHORT).show()
try {
Thread.sleep(5000)//睡眠
} catch (e: Exception) {
e.printStackTrace()
return Result.failure()
} finally {
Log.d("hh", "mainWork1 doWork:run ending...")
}
//failure retry 三种结果
return Result.success();
}
}
自定义worker--回传数据
class MainWork2(val context: Context, val workerParams: WorkerParameters) :
Worker(context, workerParams) {
//后台任务,并且是 异步放入,线程池执行runnable
override fun doWork(): Result {
Log.d("hh", "mainWork1 doWork:run starting...")
//Toast.makeText(context,"start",Toast.LENGTH_SHORT).show()
//获取传递的数据
val dataString = workerParams.inputData.getString("params")
//回传数据
val outputData = Data.Builder().putString("name", "付小影子").build()
//Result success(@NonNull Data outputData)
return Result.success(outputData);
}
}
调用请求
class WorkManagerActivity : AppCompatActivity(),
SharedPreferences.OnSharedPreferenceChangeListener {
lateinit var sp: SharedPreferences
@RequiresApi(Build.VERSION_CODES.M)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_work_manager)
//获取sp,并且设置监听
sp = getSharedPreferences(MainWork6.SP_NAME, MODE_PRIVATE);
sp.registerOnSharedPreferenceChangeListener(this)
/**
* 简单执行任务
*/
btn1.setOnClickListener {
Toast.makeText(this@WorkManagerActivity, "click", Toast.LENGTH_SHORT).show()
//创建请求 Class extends ListenableWorker> workerClass
val request = OneTimeWorkRequest.Builder(MainWork1::class.java).build()
//把请求加入队列
WorkManager.getInstance(this).enqueue(request)
}
/**
* 回传数据
*/
btn2.setOnClickListener {
//构建传递的数据
val sendData = Data.Builder().putString("params", "123456").build()
val request =
OneTimeWorkRequest.Builder(MainWork2::class.java).setInputData(sendData).build()
//利用状态机(LiveData 只有页面处于活动状态 才会接受数据) 才能接受workManager回馈的数据
WorkManager.getInstance(this@WorkManagerActivity).getWorkInfoByIdLiveData(request.id)
.observe(this@WorkManagerActivity, {
//enum State ENQUEUED RUNNING SUCCEEDED FAILED BLOCKED CANCELLED 六种状态
Log.d("hh", it.state.name)
//根据回传的状态,确定数据 Result.success(outputData);
// Result failure(@NonNull Data outputData)
// (this == SUCCEEDED || this == FAILED || this == CANCELLED)
if (it.state.isFinished) {
it.outputData.getString("name")?.let { it1 -> Log.d("hh", it1) }
}
})
WorkManager.getInstance(this@WorkManagerActivity).enqueue(request)
}
/**
* 多个任务顺序执行
*/
btn3.setOnClickListener {
//顺序执行任务 work3 work4 work5
val request1 = OneTimeWorkRequest.Builder(MainWork3::class.java).build()
val request2 = OneTimeWorkRequest.Builder(MainWork4::class.java).build()
val request3 = OneTimeWorkRequest.Builder(MainWork5::class.java).build()
//beginWith(@NonNull OneTimeWorkRequest work)
WorkManager.getInstance(this).beginWith(request1)
.then(request2)
.then(request3)
.enqueue()
//先执行work3,5 最后执行work4
//beginWith(@NonNull List work)
val requestList = listOf(request1, request3)
WorkManager.getInstance(this).beginWith(requestList)
.then(request2)
.enqueue()
}
//重复任务 多次 循环执行,轮循
btn4.setOnClickListener {
//OneTimeWorkRequest 是单次执行任务,不会轮循,都继承WorkRequest,抽象类
//重复的,多次的,循环的任务
//为了省电优化,设置的默认时间是15分钟。所以即使我们配置为10s 执行一次后台任务,也会是15分钟执行
val request =
PeriodicWorkRequest.Builder(MainWork3::class.java, 10, TimeUnit.SECONDS).build()
//因为是多次轮循,所以一直都拿不到success结果,不出错不取消的情况下,一直是 ENQUEUED RUNNING来回切换
WorkManager.getInstance(this).getWorkInfoByIdLiveData(request.id)
.observe(this, {
Log.d("hh", it.state.name) //不出错不取消的情况下,一直是 ENQUEUED RUNNING来回切换
if (it.state.isFinished) {
Log.d("hh", "任务执行结束....")
}
})
//加入队列
WorkManager.getInstance(this).enqueue(request)
//取消任务,只是表面的取消,任务还是得执行完成 cancelWorkById(request.id) cancelAllWork() cancelAllWorkByTag()
//WorkManager.getInstance(this).cancelWorkById(request.id)
}
/**
* 添加约束条件,执行后台任务
*/
btn5.setOnClickListener {
//定义约束条件
val constrains = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED) //必须是联网状态
.setRequiresCharging(true)//添加 充电中状态
.setRequiresDeviceIdle(true)//添加闲时状态
.setRequiresBatteryNotLow(true)//不是低电量状态
.build()
//创建请求,绑定约束条件
val request =
OneTimeWorkRequest.Builder(MainWork3::class.java).setConstraints(constrains).build()
//加入队列
WorkManager.getInstance(this).enqueue(request)
}
/**
* 测试 任务一直在后台运行。。利用sp写入数据,刷新到页面上
*/
btn6.setOnClickListener {
//定义约束条件
val constrains = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED) //必须是联网状态
.build()
//创建请求,绑定约束条件
val request =
OneTimeWorkRequest.Builder(MainWork6::class.java).setConstraints(constrains).build()
//加入队列
WorkManager.getInstance(this).enqueue(request)
}
}
//当sp 文件内容被改变时候,会回调此函数
override fun onSharedPreferenceChanged(p0: SharedPreferences?, p1: String?) {
tvValue.text = "后台任务数据--${sp.getInt(MainWork6.SP_KEY, 0)}"
}
}
常见面试提问
workmanager 是干嘛用的?
处理非及时任务的,比如每天同步一次数据到服务器,这种类似的需求,不是及时执行,但是又保证一定会被执行的非及时任务。
workmanager 是怎么保证,把APP退出后,还能正常运行?
记录用户的所有任务信息,并且保存的数据库中,没有保存在内存中,就是为了持久性保存记录。所有APP被杀掉后,依然可以获取所以的任务信息。然后通过广播和系统级别的服务(SystemAlertService),进行任务执行。
workmanager 任务是怎么保证一定会执行的?
Android 操作系统会在系统级别的服务中,来判断用户的约束条件,当约束条件满足时,就会执行任务,但是触发检测是采用广播的形式处理的,比如网络连接成功就触发等。
源码解析
workmanager注入说明
打包apk的时候,Android 系统会在配置清单文件中生成ContentProver作为workmanager的入口配置,执行第一次初始化。利用系统级别service,即使APP退出后台,仍旧能保证任务的执行。
源代码代码执行流程
广播执行的流程
添加的约束条件,会生成很多广播,这些广播只是个空壳子,并没有实现操作。创建了个总广播,来处理各种广播receive。