如何应对 Android 面试官 -> 启动如何进行优化(下)?玩转 Android StartUp

前言


在这里插入图片描述

本章继续上一章的启动优化讲解,主要基于手淘全链路性能优化分析 Android StartUp 启动框架;

有向无环图(DAG)算法


我们首先去 LeetCode 上看一道算法题:课程表

在这里插入图片描述
看题目,可能好多算法薄弱的人有点懵逼,转换一下思路,例如:如果你想学习 OKHttp,那么你需要一些其他的知识来辅助你学习 OKhttp
在这里插入图片描述

那么你需要学习 java 只是,学习 Socket、Https 和设计模式,然后学习了这些知识之后,来辅助你学习 OKHttp,这样的一个依赖关系;

转换到我们进行启动优化上,我们在 Application 中初始化三方 SDK 的时候,就要考虑相互之间的依赖关系,而不是一股脑的所有 SDK 都放到子线程或者延迟初始化;

这种有依赖,有方向,没有形成回环的结构就是『有向无环图』简称 DAG;

在上面那张依赖图中,剪头我们通常叫做『边』,Socket 有一个箭头指向它,那么它的入度就是 1,OKHttp 有两个箭头指向它,那么它的入度就是 2,倒过来讲就是出度,Java 的出度是 2, OKHttp 的出度是 0;

那么,我们接下来如何通过代码来实现这个『有向无环图』我们可以借助 BFS 或者 DFS,对这两个感兴趣的可以看下这个链接:图文详解 BFS DFS

拓扑排序

拓扑排序是对一个有向图构造拓扑序列的过程;图的拓扑排序不是唯一的;实现拓扑排序的整体思路是:

  • 找出图中 0 入度的顶点;
  • 依次在图中删除这些顶点,删除后再找出图中 0 入度的顶点;
  • 然后在删除…再找出…;
  • 直至删除所有顶点,即完成拓扑排序;
    在这里插入图片描述
    在这里插入图片描述

Android StartUp 具体实现


首先我们来定一个 StartUp 接口,这个接口用来创建当前任务,获取当前任务依赖了哪些任务,以及当前任务依赖了多少个任务

任务的排序

public interface Startup<T> {

    /**
     * 创建当前任务
     * @param context context
     * @return T 任务执行结果,返回值类型
     */
    T create(Context context);

    /**
     * 当前任务依赖了哪些任务,也就是入度数
     *
     * @return List<Class<? extends StartUp<?>>>
     */
    List<Class<? extends Startup<?>>> dependencies();

    /**
     * 当前任务依赖了多少个任务
     * @return int
     */
    int getDependenciesCount();
}

然后定义一个抽象类 AndroidStartup 实现 Startup 接口

public abstract class AndroidStartup<T> implements Startup<T> {
    
    /**
     * 获取依赖的任务
     * @return 依赖的任务
     */
    @Override
    public List<Class<? extends Startup<?>>> dependencies() {
        return null;
    }

    /**
     * 获取依赖的任务数
     * @return int
     */
    @Override
    public int getDependenciesCount() {
        List<Class<? extends Startup<?>>> dependencies = dependencies();
        return dependencies == null ? 0 : dependencies.size();
    }
}

这个抽象类中只实现了 dependencies 和 getDependenciesCount 接口;

然后定义了 5 个 Task;
在这里插入图片描述

CommonParamsTaskStartup 依赖 PushTaskStartup;

CuidTaskStartup 依赖 PushTaskStartup;

DeviceIdTaskStartup 依赖 CommonParamsTaskStartup

ImTaskStartup 依赖 DeviceIdTaskStartup、CuidTaskStartup

PushTaskStartup 没有任何依赖;

所以最终的有向无环图如下:
在这里插入图片描述

那么,具体是怎么实现这个拓扑排序的呢?我们来看下排序规则:

/**
 * 拓扑排序
 * @param startupList startupList
 * @return StartupSortStore
 */
public static StartupSortStore sort(List<? extends Startup<?>> startupList) {

    // 将所有的任务存入到一个map中
    Map<Class<? extends Startup>, Startup<?>> startupMap = new HashMap<>();

    // 入读表,记录每个任务的依赖数
    Map<Class<? extends Startup>, Integer> inDegreeMap = new HashMap<>();
    // 记录每个任务的依赖任务
    Map<Class<? extends Startup>, List<Class<? extends Startup>>> startupChildrenMap = new HashMap<>();
    // 记录入度为 0 的任务
    Deque<Class<? extends Startup>> zeroDegree = new ArrayDeque<>();
    // 遍历所有的任务
    for (Startup<?> startup : startupList) {
        startupMap.put(startup.getClass(), startup);
        // 获取每个任务的依赖数
        int dependenciesCount = startup.getDependenciesCount();
        // 存入入度表中
        inDegreeMap.put(startup.getClass(), dependenciesCount);

        if (dependenciesCount == 0) {
       
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值