android开发学习

Android WorkManager 使用及思考

2021-01-01  本文已影响0人  虞_18bd

回想到之前的一个面试,面试官问我: 如何解决应用启动时,因为需要初始化的三方库过多时,导致的卡顿或是项目功能对三方库初始化有依赖时如何解决,用work可以解决么?

这个问题涉及到几个方面

1.初始化卡顿问题

2.初始化速度,以及初始化完成后如何通知UI层

3.work的使用

1.为什么会初始化卡顿,我第一反应是不是有些任务在UI线程上工作了,因为一般三方库初始化都在Application,并不依赖于UI的逻辑,在项目启动时,初始化其实就已经开始了,就算有依赖链的问题,用RxAndroid的flatmap也能很好的解决依赖问题。

2.初始化速度,那应该是三方库关心的问题,至于通知的话,无论是使用单例的LiveData,还是用如EventBus的通知模式,甚至是广播的形式,都是可以的。

3.重点就是work,之前我也是接触过work的,是google的一个demo中用于处理图片的高斯模糊中用到了workmanager,我的第一印象就是一个封装过的异步任务处理库,可以在一些特殊情况下对之前未完成的任务继续。

WorkManager

到底是什么?WorkManager 是一个 API,使您可以轻松调度那些即使在退出应用或重启设备时仍应运行的可延期异步任务

说白了还是异步任务封装的功能库 =。=

那它出现的目的呢?毕竟我们已经有了那么多异步任务库:

WorkManager API 是一个针对先前的 Android 后台调度 API(包括 FirebaseJobDispatcherGcmNetworkManagerJobScheduler)的合适的建议替换组件

到这里我就有点蒙蔽了,这三个库除了第三个,我知道是啥,剩下两个我是完全不知道(原来我才是小丑)

那先从第三个说起吧(JobScheduler)任务调度器

它主要功能是监听系统的一系列广播,然后决定是否执行任务:

举例一个场景: 我们的应用需要推送下载最新版本的api,用户手机收到了推送,但是当前是在弱网情况,或者电量很低的情况,这时候用户下载apk肯定是不合适的,甚至弹出询问都是一种很惹人反感的行为,所以就需要任务调度器来决定何时才是弹出询问,或是自动下载的正确时机。

至于FirebaseJobDispatcher和GcmNetworkManager

image-20210101212805083.png image-20210101212905249.png

很好在我发现它们的时候,它们已经落幕了(后面发现还是我太年轻了,原来我才是小丑)

说了这么多 workManager 到底如何工作的呢

image-20210101213050318.png

ok,低版本的原来还是用Gcm但是那不关键,看来workmanager就是二次对JobScheduler的封装

直接上码

官方demo

//FilterActivity.kt
//google在致力于让代码变得更优雅(装b)

findViewById<View>(R.id.go).setOnClickListener {
    val applyWaterColor = isChecked(R.id.filter_watercolor)
    val applyGrayScale = isChecked(R.id.filter_grayscale)
    val applyBlur = isChecked(R.id.filter_blur)
    val save = isChecked(R.id.save)
    val upload = isChecked(R.id.upload)
    // 这里有个建造者模式 我们进去瞅瞅他们做了啥
    val imageOperations = ImageOperations.Builder(applicationContext, mImageUri!!)
            .setApplyWaterColor(applyWaterColor)
            .setApplyGrayScale(applyGrayScale)
            .setApplyBlur(applyBlur)
            .setApplySave(save)
            .setApplyUpload(upload)
            .build()

    mViewModel.apply(imageOperations)
internal class ImageOperations private constructor(val continuation: WorkContinuation) {

    internal class Builder(private val mContext: Context, private val mImageUri: Uri) {
        private var mApplyWaterColor: Boolean = false
        private var mApplyGrayScale: Boolean = false
        private var mApplyBlur: Boolean = false
        private var mApplySave: Boolean = false
        private var mApplyUpload: Boolean = false
        ......
        /**
         * Creates the [WorkContinuation] depending on the list of selected filters.
         *
         * @return the instance of [WorkContinuation].
         */
        // build这里就是启动workManager的任务了 代码太长 我删掉一部分
        fun build(): ImageOperations {
            var hasInputData = false
            // 这里像是一个单例 启动了work
            var continuation = WorkManager.getInstance(mContext)
                    // 这是任务标识 + 任务的工作要求 + 将要被执行的任务(其实也支持任务链)
                    .beginUniqueWork(Constants.IMAGE_MANIPULATION_WORK_NAME,
                            ExistingWorkPolicy.REPLACE,
                            OneTimeWorkRequest.from(CleanupWorker::class.java))

            if (mApplyWaterColor) {
                // 新任务
                val waterColor = OneTimeWorkRequestBuilder<WaterColorFilterWorker>()
                        .setInputData(createInputData())
                        .build()
                continuation = continuation.then(waterColor) // 加入任务链
                hasInputData = true
            }
        }

        private fun createInputData(): Data {
            return workDataOf(Constants.KEY_IMAGE_URI to mImageUri.toString())
        }
    }
}

这是ExistingWorkPolicy的枚举说明ExistingWorkPolicy

//CleanupWorker.kt

//任务本体
class CleanupWorker(appContext: Context, workerParams: WorkerParameters)
    : Worker(appContext, workerParams) {

    companion object {
        private const val TAG = "CleanupWorker"
    }
    // 执行的任务
    override fun doWork(): Result {
        try {
            val outputDirectory = File(applicationContext.filesDir, Constants.OUTPUT_PATH)
            if (outputDirectory.exists()) {
                val entries = outputDirectory.listFiles()
                if (entries != null && entries.isNotEmpty()) {
                    for (entry in entries) {
                        val name = entry.name
                        if (!TextUtils.isEmpty(name) && name.endsWith(".png")) {
                            val deleted = entry.delete()
                            Log.i(TAG, String.format("Deleted %s - %s", name, deleted))
                        }
                    }
                }
            }
            return Result.success()
        } catch (exception: Exception) {
            Log.e(TAG, "Error cleaning up", exception)
            return Result.failure()
        }
    }
}

上面就是一套链式任务的调用流程,确实很优雅(装b)

说到这里如果结束是不是觉得少了点什么

确实,之前说好的限制条件呢? 晃点我?

Constraints

// 这里可以生成限制条件
Constraints myConstraints = new Constraints.Builder()    .setRequiresDeviceIdle(true)    
    .setRequiresCharging(true) 
    .build();// Many other constraints are available, see the    // Constraints.Builder reference     .build();
// 在生成任务时绑定限制条件
OneTimeWorkRequest compressionWork = new OneTimeWorkRequest.Builder(CompressWorker.class)
     .setConstraints(myConstraints)
     .build();

这就大公告成了。但是它真的适合用于做看上去很简单的三方库初始化么?

可以但是没必要吧,但确实是一系列的思路

上一篇 下一篇

猜你喜欢

热点阅读