2024年安卓最全Android 启动优化(四)- AnchorTask 是怎么实现的,2024年最新阿里面试官手册

最后

想要了解更多关于大厂面试的同学可以点赞支持一下,除此之外,我也分享一些优质资源,包括:Android学习PDF+架构视频+源码笔记高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 这几块的内容。非常适合近期有面试和想在技术道路上继续精进的朋友。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!


IAnchorTask

首先,我们定义一个 IAnchorTask 接口,主要有一个方法

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

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

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

  • fun getDependsTaskList(): List<class&gt;?</class 方法返回前置任务依赖,默认值是返回 null.

  • 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 getDependsTaskList(): List<Class>?

28

29    /**

30     * 任务被执行的时候回调

31     */

32    fun run()

33

34}

它有一个实现类 AnchorTask,增加了 await 和 countdown 方法

  • await 方法,调用它,当前任务会等待

  • countdown() 方法,如果当前计数器值 > 0,会减一,否则,什么也不操作

1abstract class AnchorTask : IAnchorTask {

2

3    private val countDownLatch: CountDownLatch = CountDownLatch(getListSize())

4    private fun getListSize() = getDependsTaskList()?.size ?: 0

5

6    companion object {

7        const val TAG = “AnchorTask”

8    }

9

10    /**

11     * self call,await

12     */

13    fun await() {

14        countDownLatch.await()

15    }

16

17    /**

18     * parent call, countDown

19     */

20    fun countdown() {

21        countDownLatch.countDown()

22    }

23}

排序实现

无环图的拓扑排序,这里采用的是 BFS 算法。具体的可以见 AnchorTaskUtils#getSortResult 方法,它有三个参数

  • list 存储所有的任务

  • taskMap: MutableMap<class, AnchorTask&gt; = HashMap()</class存储所有的任务,key 是 Class

,value 是 AnchorTask

  • taskChildMap: MutableMap<class, ArrayList<class&gt;?&gt; =<br /> HashMap()</class</class,储存当前任务的子任务, key 是当前任务的 class,value 是 AnchorTask 的 list

算法思想

  1. 首先找出所有入度为 0 的队列,用 queue 变量存储

  2. 当队列不为空,进行循环判断。

  • 从队列 pop 出,添加到结果队列

  • 遍历当前任务的子任务,通知他们的入度减一(其实是遍历 taskChildMap),如果入度为 0,添加到队列 queue 里面

  • 当结果队列和 list size 不相等试,证明有环

1    @JvmStatic

2    fun getSortResult(

3        list: MutableList, taskMap: MutableMap<Class, AnchorTask>,

4        taskChildMap: MutableMap<Class, ArrayList<Class>?>

5    ): MutableList {

6        val result = ArrayList()

7        // 入度为 0 的队列

8        val queue = ArrayDeque()

9        val taskIntegerHashMap = HashMap<Class, Int>()

10

11        // 建立每个 task 的入度关系

12        list.forEach { anchorTask: AnchorTask ->

13            val clz = anchorTask.javaClass

14            if (taskIntegerHashMap.containsKey(clz)) {

15                throw AnchorTaskException(“anchorTask is repeat, anchorTask is  a n c h o r T a s k ,   l i s t   i s   anchorTask, list is  anchorTask, list is list”)

16            }

17

18            val size = anchorTask.getDependsTaskList()?.size ?: 0

19            taskIntegerHashMap[clz] = size

20            taskMap[clz] = anchorTask

21            if (size == 0) {

22                queue.offer(anchorTask)

23            }

24        }

25

26        // 建立每个 task 的 children 关系

27        list.forEach { anchorTask: AnchorTask ->

28            anchorTask.getDependsTaskList()?.forEach { clz: Class ->

29                var list = taskChildMap[clz]

30                if (list == null) {

31                    list = ArrayList<Class>()

32                }

33                list.add(anchorTask.javaClass)

34                taskChildMap[clz] = list

35            }

36        }

37

38        // 使用 BFS 方法获得有向无环图的拓扑排序

39        while (!queue.isEmpty()) {

40            val anchorTask = queue.pop()

41            result.add(anchorTask)

42            val clz = anchorTask.javaClass

43            taskChildMap[clz]?.forEach { // 遍历所有依赖这个顶点的顶点,移除该顶点之后,如果入度为 0,加入到改队列当中

44                var result = taskIntegerHashMap[it] ?: 0

45                result–

46                if (result == 0) {

47                    queue.offer(taskMap[it])

48                }

49                taskIntegerHashMap[it] = result

50            }

51        }

52

53        // size 不相等,证明有环

54        if (list.size != result.size) {

55            throw AnchorTaskException(“Ring appeared,Please check.list is  l i s t ,   r e s u l t   i s   list, result is  list, result is result”)

56        }

57

58        return result

59

60    }

AnchorTaskDispatcher

AnchorTaskDispatcher 这个类很重要,有向无环图的拓扑排序和多线程的依赖唤醒,都是借助这个核心类完成的。

它主要有几个成员变量

1// 存储所有的任务

2    private val list: MutableList = ArrayList()

3

4    // 存储所有的任务,key 是 Class,value 是 AnchorTask

5    private val taskMap: MutableMap<Class, AnchorTask> = HashMap()

6

7    // 储存当前任务的子任务, key 是当前任务的 class,value 是 AnchorTask 的 list

8    private val taskChildMap: MutableMap<Class, ArrayList<Class>?> =

9        HashMap()

10

11    // 拓扑排序之后的主线程任务

12    private val mainList: MutableList = ArrayList()

13

14    // 拓扑排序之后的子线程任务

15    private val threadList: MutableList = ArrayList()

16

17    //需要等待的任务总数,用于阻塞

18    private lateinit var countDownLatch: CountDownLatch

19

20    //需要等待的任务总数,用于CountDownLatch

21    private val needWaitCount: AtomicInteger = AtomicInteger()

它有一个比较重要的方法 setNotifyChildren(anchorTask: AnchorTask) ,有一个方法参数 AnchorTask,它的作用是通知该任务的子任务,当前任务执行完毕,入度数减一。

1    /**

2     *  通知 child countdown,当前的阻塞任务书也需要 countdown

3     */

4    fun setNotifyChildren(anchorTask: AnchorTask) {

5        taskChildMap[anchorTask::class.java]?.forEach {

6            taskMap[it]?.countdown()

7        }

8        if (anchorTask.needWait()) {

9            countDownLatch.countDown()

10        }

11    }

接下来看一下 start 方法

1fun start(): AnchorTaskDispatcher {

2        if (Looper.myLooper() != Looper.getMainLooper()) {

3            throw AnchorTaskException(“start method should be call on main thread”)

4        }

最后附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题 (含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总)

面试成功其实是必然的,因为我做足了充分的准备工作,包括刷题啊,看一些Android核心的知识点,看一些面试的博客吸取大家面试的一些经验,下面这份PDF是我翻阅了差不多1个月左右一些Android大博主的博客从他们那里取其精华去其糟泊所整理出来的一些Android的核心知识点, 全部都是精华中的精华,我能面试到现在资深开发人员跟我整理的这本Android核心知识点有密不可分的关系,在这里本着共赢的心态分享给各位朋友。

这份PDF囊括了JVM,Java集合,Java多线程并发,Java基础,生命周期,微服务, 进程,Parcelable 接口,IPC,屏幕适配,线程异步,ART,架构,Jetpack,NDK开发,计算机网络基础,类加载器,Android 开源库源码分析,设计模式汇总,Gradle 知识点汇总…

由于篇幅有限,就不做过多的介绍,大家请自行脑补

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

id核心知识点有密不可分的关系,在这里本着共赢的心态分享给各位朋友。
[外链图片转存中…(img-RpqcXE3g-1715731103655)]

这份PDF囊括了JVM,Java集合,Java多线程并发,Java基础,生命周期,微服务, 进程,Parcelable 接口,IPC,屏幕适配,线程异步,ART,架构,Jetpack,NDK开发,计算机网络基础,类加载器,Android 开源库源码分析,设计模式汇总,Gradle 知识点汇总…

由于篇幅有限,就不做过多的介绍,大家请自行脑补

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 12
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值