Android 启动优化(五)- AnchorTask 1.0.0 版本正式

今天,更新一下 Android 启动优化有向无环图系列的最后一篇文章。最近一段时间,暂时不会更新这方面的文章了。系列文章汇总如下:

Android 启动优化(一) - 有向无环图

Android 启动优化(二) - 拓扑排序的原理以及解题思路

Android 启动优化(三)- AnchorTask 开源了

Android 启动优化(四)-  AnchorTask 是怎么实现的

更新说明

  1. 之前的 0.1.0 版本 配置前置依赖任务,是通过 AnchorTask getDependsTaskList 的方式,他是通过 className 找到 AnchorTask,并且内聚在当前的 AnchorTask 中,从全局的角度看 ,这种方式不太直观,1.0.0 放弃了这种方式,参考阿里 Alpha 的方式,通过 addTask(TASK_NAME_THREE).afterTask(TASK_NAME_ZERO, TASK_NAME_ONE)

  2. 1.0.0 版本新增了 Project 类,并增加 OnProjectExecuteListener 监听

  3. 1.0.0 版本新增 OnGetMonitorRecordCallback 监听,方便统计各个任务的耗时

说明

Android 启动优化,大家第一时间可能会想到异步加载。将耗时任务放到子线程加载,等到所有加载任务加载完成之后,再进入首页。

多线程异步加载方案确实是 ok 的。但如果遇到前后依赖的关系呢。比如任务2 依赖于任务 1,这时候要怎么解决呢。

假设我们有这样的任务依赖

我们要怎么使用它呢

 1        val project =
 2            AnchorProject.Builder().setContext(context).setLogLevel(LogUtils.LogLevel.DEBUG)
 3                .setAnchorTaskCreator(ApplicationAnchorTaskCreator())
 4                .addTask(TASK_NAME_ZERO)
 5                .addTask(TASK_NAME_ONE)
 6                .addTask(TASK_NAME_TWO)
 7                .addTask(TASK_NAME_THREE).afterTask(TASK_NAME_ZERO, TASK_NAME_ONE)
 8                .addTask(TASK_NAME_FOUR).afterTask(TASK_NAME_ONE, TASK_NAME_TWO)
 9                .addTask(TASK_NAME_FIVE).afterTask(TASK_NAME_THREE, TASK_NAME_FOUR)
10                .build()
11        project.start().await()
 1class ApplicationAnchorTaskCreator : IAnchorTaskCreator {
 2    override fun createTask(taskName: String): AnchorTask? {
 3        when (taskName) {
 4            TASK_NAME_ZERO -> {
 5                return AnchorTaskZero()
 6            }
 7
 8            TASK_NAME_ONE -> {
 9                return AnchorTaskOne()
10            }
11            TASK_NAME_TWO -> {
12                return AnchorTaskTwo()
13            }
14            TASK_NAME_THREE -> {
15                return AnchorTaskThree()
16            }
17            TASK_NAME_FOUR -> {
18                return AnchorTaskFour()
19            }
20            TASK_NAME_FIVE -> {
21                return AnchorTaskFive()
22            }
23        }
24        return null
25    }
26
27}

Demo 跑起来,可以看到预期的效果。

基本使用

第一步:在 moulde build.gradle 配置远程依赖

1implementation 'com.xj.android:anchortask:1.0.0'

最新的版本号可以看这里 lastedt version

第二步:自定义 AnchorTaskZero,继承 AnchorTask,并指定 taskName,注意 taskName必须是唯一的,因为我们会根据 taskName 找到相应的 AnchorTask 重写相应的方法

 1class AnchorTaskZero() : AnchorTask(TASK_NAME_ZERO) {
 2    override fun isRunOnMainThread(): Boolean {
 3        return false
 4    }
 5
 6    override fun run() {
 7        val start = System.currentTimeMillis()
 8        try {
 9            Thread.sleep(300)
10        } catch (e: Exception) {
11        }
12        LogUtils.i(
13            TAG, "AnchorTaskOne: " + (System.currentTimeMillis() - start)
14        )
15    }
16}

如果任务 三 依赖任务 二,任务 一,可以这样写

addTask(TASK_NAME_THREE).afterTask(TASK_NAME_ZERO, TASK_NAME_ONE)

最后,通过 project.start() 方法启动, 如果需要阻塞等待,调用 await() 方法

 AnchorProject.Builder().setContext(context).setLogLevel(LogUtils.LogLevel.DEBUG)
                 .setAnchorTaskCreator(ApplicationAnchorTaskCreator())
                 .addTask(TASK_NAME_ZERO)
                 .addTask(TASK_NAME_ONE)
                 .addTask(TASK_NAME_TWO)
                 .addTask(TASK_NAME_THREE).afterTask(TASK_NAME_ZERO, TASK_NAME_ONE)
                 .addTask(TASK_NAME_FOUR).afterTask(TASK_NAME_ONE, TASK_NAME_TWO)
                 .addTask(TASK_NAME_FIVE).afterTask(TASK_NAME_THREE, TASK_NAME_FOUR)
                 .build()
project.start().await()

监听任务回调

 1project.addListener(object : OnProjectExecuteListener {
 2
 3            // project 开始执行的时候
 4            override fun onProjectStart() {
 5                com.xj.anchortask.LogUtils.i(MyApplication.TAG, "onProjectStart ")
 6            }
 7
 8            // project 执行一个 task 完成的时候
 9            override fun onTaskFinish(taskName: String) {
10                com.xj.anchortask.LogUtils.i(
11                    MyApplication.TAG,
12                    "onTaskFinish, taskName is $taskName"
13                )
14            }
15
16            // project 执行完成的时候
17            override fun onProjectFinish() {
18                com.xj.anchortask.LogUtils.i(MyApplication.TAG, "onProjectFinish ")
19            }
20
21        })

添加每个任务执行耗时回调

 1project.onGetMonitorRecordCallback = object : OnGetMonitorRecordCallback {
 2
 3            // 所有 task 执行完毕会调用这个方法,Map 存储了 task 的执行时间, key 是 taskName,value 是时间,单位毫秒
 4            override fun onGetTaskExecuteRecord(result: Map<String?, Long?>?) {
 5                onGetMonitorRecordCallback?.onGetTaskExecuteRecord(result)
 6            }
 7
 8            // 所有 task 执行完毕会调用这个方法,costTime 执行时间
 9            override fun onGetProjectExecuteTime(costTime: Long) {
10                onGetMonitorRecordCallback?.onGetProjectExecuteTime(costTime)
11            }
12
13        }

AnchorTask 介绍

AnchorTask 实现了 IAnchorTask 接口,主要有几个方法

  • isRunOnMainThread(): Boolean表示是否在主线程运行,默认值是 false

  • priority(): Int 方法 表示线程的优先级别,默认值是 Process.THREAD_PRIORITY_FOREGROUND

  • needWait() 表示当我们调用 AnchorTaskDispatcher await 时,是否需要等待,return true,表示需要等待改任务执行结束,AnchorTaskDispatcher await 方法才能继续往下执行。

  • fun run() 方法,表示任务执行的时候

 1interface IAnchorTask : IAnchorCallBack {
 2
 3    /**
 4     * 是否在主线程执行
 5     */
 6    fun isRunOnMainThread(): Boolean
 7
 8    /**
 9     * 任务优先级别
10     */
11    @IntRange(
12        from = Process.THREAD_PRIORITY_FOREGROUND.toLong(),
13        to = Process.THREAD_PRIORITY_LOWEST.toLong()
14    )
15    fun priority(): Int
16
17    /**
18     * 调用 await 方法,是否需要等待改任务执行完成
19     * true 不需要
20     * false 需要
21     */
22    fun needWait(): Boolean
23
24    /**
25     * 任务被执行的时候回调
26     */
27    fun run()
28
29}
 1class AnchorTaskOne : AnchorTask() {
 2    override fun isRunOnMainThread(): Boolean {
 3        return false
 4    }
 5
 6    override fun run() {
 7        val start = System.currentTimeMillis()
 8        try {
 9            Thread.sleep(300)
10        } catch (e: Exception) {
11        }
12        LogUtils.i(
13            TAG, "AnchorTaskOne: " + (System.currentTimeMillis() - start)
14        )
15    }
16
17}

监听任务的回调

 1val anchorTask = AnchorTaskTwo()
 2        anchorTask.addCallback(object : IAnchorCallBack {
 3            override fun onAdd() {
 4                com.xj.anchortask.LogUtils.i(TAG, "onAdd: $anchorTask")
 5            }
 6
 7            override fun onStart() {
 8                com.xj.anchortask.LogUtils.i(TAG, "onStart:$anchorTask ")
 9            }
10
11            override fun onFinish() {
12                com.xj.anchortask.LogUtils.i(TAG, "onFinish:$anchorTask ")
13            }
14
15        })

总结

AnchorTask 的原理不复杂,本质是有向无环图与多线程知识的结合。

  1. 根据 BFS 构建出有向无环图,并得到它的拓扑排序

  2. 在多线程执行过程中,我们是通过任务的子任务关系和 CounDownLatch 确保先后执行关系的

    1. 前置任务没有执行完毕的话,等待,执行完毕的话,往下走

    2. 执行任务

    3. 通知子任务,当前任务执行完毕了,相应的计数器(入度数)要减一。

AnchorTask:https://github.com/gdutxiaoxu/AnchorTask

想看 1.0.0 版本的具体实现,可以看这篇文章。AnchorTask 1.0.0 原理说明。

Android 启动优化(一) - 有向无环图

Android 启动优化(二) - 拓扑排序的原理以及解题思路

Android 启动优化(三)- AnchorTask 开源了

Android 启动优化(四)-  AnchorTask 是怎么实现的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值