Android JetPack App Startup 使用及源码浅析(二)

简介: Android JetPack App Startup 使用及源码浅析

AppStartUp 进阶使用


手动初始化


上面我们讲解了 AppStartUp 的基本使用步骤,如果我们不像在 Application onCreate 之前执行我们的 ExampleLoggerInitializer,要怎么使用呢?


其实很简单,


第一步,在 AndroidManifest InitializationProvider 中移除 移除 <meta-data 标签

在代码中调用 AppInitializer initializeComponent 方法初始化

<provider
    android:name="androidx.startup.InitializationProvider"
    android:authorities="${applicationId}.androidx-startup"
    android:exported="false"
    tools:node="merge">
</provider>


AppInitializer.getInstance(context).initializeComponent(ExampleLoggerInitializer::class.java)


App start up 源码分析


我们首先来看一下他的结构,只有简单的几个类


929e2990e264283525f077d3f4af5c17_a8689549ab9f4d1e94e53a246059f455.png


Initializer 这个接口就没有必要说了,很简单,只有两个方法。


InitializationProvider 继承了 ContentProvider,借助了 ContentProvider 会在 Application onCreate 之前执行的特点。来执行一些初始化操作。


public final class InitializationProvider extends ContentProvider {
    @Override
    public boolean onCreate() {
        Context context = getContext();
        if (context != null) {
            AppInitializer.getInstance(context).discoverAndInitialize();
        } else {
            throw new StartupException("Context cannot be null");
        }
        return true;
    }
    ----
}

我们可以看到在 onCreate 方法中调用 AppInitializer discoverAndInitialize 方法进行初始化。


  1. 找到 AndroidManifest InitializationProvider 下的 meta 便签
  2. 判断 meta 便签下 value 的值是不是 androidx.startup
  3. 判断是不是实现 Initializer 接口,是的话,执行 doInitialize 方法


void discoverAndInitialize() {
    try {
        Trace.beginSection(SECTION_NAME);
        ComponentName provider = new ComponentName(mContext.getPackageName(),
                InitializationProvider.class.getName());
        ProviderInfo providerInfo = mContext.getPackageManager()
                .getProviderInfo(provider, GET_META_DATA);
        Bundle metadata = providerInfo.metaData;
        String startup = mContext.getString(R.string.androidx_startup);
        // 找到 metadata 标签
        if (metadata != null) {
            Set<Class<?>> initializing = new HashSet<>();
            Set<String> keys = metadata.keySet();
            for (String key : keys) {
                String value = metadata.getString(key, null);
                // 判断 value 的值是不是 androidx.startup
                // 判断是不是实现了 Initializer 接口,是的话,反射初始化
                if (startup.equals(value)) {
                    Class<?> clazz = Class.forName(key);
                    if (Initializer.class.isAssignableFrom(clazz)) {
                        Class<? extends Initializer<?>> component =
                                (Class<? extends Initializer<?>>) clazz;
                        mDiscovered.add(component);
                        if (StartupLogger.DEBUG) {
                            StartupLogger.i(String.format("Discovered %s", key));
                        }
                        doInitialize(component, initializing);
                    }
                }
            }
        }
    } catch (PackageManager.NameNotFoundException | ClassNotFoundException exception) {
        throw new StartupException(exception);
    } finally {
        Trace.endSection();
    }
}

doInitialize 方法


<T> T doInitialize(
        @NonNull Class<? extends Initializer<?>> component,
        @NonNull Set<Class<?>> initializing) {
    synchronized (sLock) {
        boolean isTracingEnabled = Trace.isEnabled();
        try {
            if (isTracingEnabled) {
                // Use the simpleName here because section names would get too big otherwise.
                Trace.beginSection(component.getSimpleName());
            }
            if (initializing.contains(component)) {
                String message = String.format(
                        "Cannot initialize %s. Cycle detected.", component.getName()
                );
                throw new IllegalStateException(message);
            }
            Object result;
            if (!mInitialized.containsKey(component)) {
                initializing.add(component);
                try {
                    Object instance = component.getDeclaredConstructor().newInstance();
                    Initializer<?> initializer = (Initializer<?>) instance;
                    List<Class<? extends Initializer<?>>> dependencies =
                            initializer.dependencies();
                    if (!dependencies.isEmpty()) {
                        for (Class<? extends Initializer<?>> clazz : dependencies) {
                            if (!mInitialized.containsKey(clazz)) {
                                doInitialize(clazz, initializing);
                            }
                        }
                    }
                    if (StartupLogger.DEBUG) {
                        StartupLogger.i(String.format("Initializing %s", component.getName()));
                    }
                    result = initializer.create(mContext);
                    if (StartupLogger.DEBUG) {
                        StartupLogger.i(String.format("Initialized %s", component.getName()));
                    }
                    initializing.remove(component);
                    mInitialized.put(component, result);
                } catch (Throwable throwable) {
                    throw new StartupException(throwable);
                }
            } else {
                result = mInitialized.get(component);
            }
            return (T) result;
        } finally {
            Trace.endSection();
        }
    }
}

可以看到在执行初始化的时候,先判断了是否有依赖项,有的话先执行依赖项的初始化


小结


  • App start up,我觉得他的设计初衷应该是为了收拢 ContentProvider,实际上对启动优化的帮助不是很大。
  • 如果你的项目都是同步初始化的话,并且使用到了多个ContentProvider,App Startup可能有一定的优化空间,毕竟统一到了一个ContentProvider中,同时支持了简单的顺序依赖。
  • ContentProvider 初始化的这个思想,目前有挺多 SDK 这么做的,像 FaceBook 广告 SDK,友盟 SDk 等。我们在启动优化的时候,是不是可以去掉相应的 ContentProvider,减少创建 Provider 的时间
  • 实际项目中 启动优化,大多数啊都会使用多线程异步加载,这时候 App start up 就显得很鸡肋了,没用


参考博客: Jetpack新成员,App Startup一篇就懂


本文收录于 github.com/gdutxiaoxu/… 「Android学习+面试指南」一份涵盖大部分 Android 程序员所需要掌握的核心知识。准备 Android 面试,首选 AndroidGuide!


相关文章
|
21小时前
|
传感器 人工智能 数据可视化
Java智慧工地监管一体化云平台APP源码 SaaS模式
安全隐患排查 1.可在电脑端、手机端对安全隐患数据进行记录、查询 2.能够实现安全隐患发起、整改、复查的闭环管理 3.具备对安全隐患数据进行统计、可视化分析、信息推送等功能 4.包含对危险性较大的分部分项工程进行巡查记录功能
11 4
|
2天前
|
安全 Java 数据挖掘
当 App 有了系统权限,真的可以为所欲为? Android Performance Systrace
当 App 有了系统权限,真的可以为所欲为? Android Performance Systrace 转载自: https://androidperformance.com/2023/05/14/bad-android-app-with-system-permissions/#/0-Dex-%E6%96%87%E4%BB%B6%E4%BF%A1%E6%81%AF
18 0
|
2天前
|
监控 安全 数据可视化
Java数字孪生智慧工地数据大屏APP源码
高支模监测:高支模立杆及倾斜角度,高支模立杆的荷载,架体的水平位移以及模板沉降情况,当检测数据超过预警值时,实时报警。
11 0
|
18天前
|
前端开发
自适应APP下载页HTML源码
自适应APP下载页HTML源码
9 0
自适应APP下载页HTML源码
|
25天前
|
Android开发 开发者 iOS开发
APP开发后如何上架,上架Android应用市场前要准备什么
移动应用程序(APP)的开发已经成为现代企业和开发者的常见实践。然而,开发一个成功的APP只是第一步,将其上架到应用商店让用户下载和使用是实现其潜力的关键一步。
|
25天前
|
开发框架 物联网 数据库
89个android学习样例源码
89个android学习样例源码
35 0
|
25天前
|
算法 Java 定位技术
分享104个益智休闲安卓游戏源码,总有一款适合你
分享104个益智休闲安卓游戏源码,总有一款适合你
23 1
|
25天前
|
编解码 移动开发 人工智能
分享4个策略经营、5动作冒险、8角色扮演、8体育竞速、18飞行射击和30棋牌安卓游戏源码
分享4个策略经营、5动作冒险、8角色扮演、8体育竞速、18飞行射击和30棋牌安卓游戏源码
19 0
|
25天前
|
存储 缓存 JavaScript
基于AutoJs7实现的薅羊毛App专业版源码大分享
基于AutoJs7实现的薅羊毛App专业版源码大分享
20 1
|
26天前
|
编解码 移动开发 人工智能
android游戏源码
android游戏源码
33 0

相关产品

  • 云迁移中心