分享好友 最新资讯首页 最新资讯分类 切换频道
2024年Java最新Jetpack 全家桶之 App Startup 看完源码后真不是你们说的那样,2024BAT大厂Java社招最全面试题
2024-12-26 20:39

本人面试腾讯,阿里,百度等企业总结下来的面试经历,都是真实的,分享给大家

2024年Java最新Jetpack 全家桶之 App Startup 看完源码后真不是你们说的那样,2024BAT大厂Java社招最全面试题

准确的说这里又分为两部分

  1. Java刷题
  2. 算法刷题

Java刷题:此份文档详细记录了千道面试题与详解

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

清单文件声明(被依赖的其他 Initializer 可以不用显式声明,lint 检查会 check 这项

<provider

android:name=“androidx.startup.InitializationProvider”

android:authorities=“${applicationId}.androidx-startup”

android:exported=“false”

tools:node=“merge”>

<meta-data android:name=“com.example.ExampleLoggerInitializer”

android:value=“androidx.startup” />

一般手动用法

除过上面自动用法,我们还可以手动使用,手动使用需要先将清单 meta 中的 remove,然后在你想初始化的地方如下调用

//【工匠若水 加微信 yanbo373131686 联系我,关注微信公众号:码农每日一题 未经允许严禁转载 https://blog.csdn.net/yanbober】

AppInitializer.getInstance(context)

.initializeComponent(ExampleLoggerInitializer::class.java)

清单文件移除写法如下

<provider

android:name=“androidx.startup.InitializationProvider”

android:authorities=“${applicationId}.androidx-startup”

tools:node=“remove” />

<provider

android:name=“androidx.startup.InitializationProvider”

android:authorities=“${applicationId}.androidx-startup”

android:exported=“false”

tools:node=“merge”>

<meta-data android:name=“com.example.ExampleLoggerInitializer”

tools:node=“remove” />

特殊用法

有时你可能会有这么一种需求,三方 SDK 提供了 AarExampleInitializer(dependencies 为空,其 aar 的清单文件也声明了类似如下

<provider

android:name=“androidx.startup.InitializationProvider”

android:authorities=“${applicationId}.androidx-startup”

android:exported=“false”

tools:node=“merge”>

<meta-data android:name=“com.example.AarExampleInitializer”

android:value=“androidx.startup” />

你想在你用这个 aar 的模块中让 AarExampleInitializer 初始化依赖其他 SDK 初始化,那你需要在你自己的模块中写一个(AarExampleInitializer 一定可以被继承,因为 App Startup 要求 Initializer 是 public 的,然后重写其 dependencies 方法为你想依赖的,接着在你自己主模块的清单中如下如下操作

//【工匠若水 加微信 yanbo373131686 联系我,关注微信公众号:码农每日一题 未经允许严禁转载 https://blog.csdn.net/yanbober】

<provider

android:name=“androidx.startup.InitializationProvider”

android:authorities=“${applicationId}.androidx-startup”

android:exported=“false”

tools:node=“merge”>

<meta-data android:name=“com.example.OverAarExampleInitializer”

android:value=“androidx.startup” />

<meta-data android:name=“com.example.AarExampleInitializer”

tools:node=“remove” />

如上即可实现需求。反之你想让其他模块初始化依赖 AarExampleInitializer,则只用在其他模块中依赖声明即可。

源码分析

================================================================

App Startup 包的整体源码结构如下

下面我们分析下其源码,首先按照使用来说,我们需要先实现的是各个 SDK 的初始化约定,如下

//【工匠若水 加微信 yanbo373131686 联系我,关注微信公众号:码农每日一题 未经允许严禁转载 https://blog.csdn.net/yanbober】

public interface Initializer {

@NonNull

T create(@NonNull Context context);

@NonNull

List<Class<? extends Initializer<?>>> dependencies();

}

当我们实现了后如果采用自动用法,则 app startup 巧妙的利用了 ContentProvider 初始化时机实现,其源码清单中如下

<manifest xmlns:android=“http://schemas.android.com/apk/res/android”

xmlns:tools=“http://schemas.android.com/tools”

package=“androidx.startup” >

<uses-sdk

android:minSdkVersion=“14”

android:targetSdkVersion=“30” />

<provider

android:name=“androidx.startup.InitializationProvider”

android:authorities=“${applicationId}.androidx-startup”

android:exported=“false”

tools:node=“merge” />

可以看到,其巧妙的利用了 merge node 进行多个模块的合并,并且其提供了唯一的进行统管。我们每个都是其节点内部的一个 meta-data 项,如下

<meta-data android:name=“com.example.OverAarExampleInitializer”

android:value=“androidx.startup” />

这些 meta-data 最终都会在中进行解析调用,由于 app 启动时 InitializationProvider 会被自动调用,所以接下来我们将流程转到 InitializationProvider,如下

//【工匠若水 加微信 yanbo373131686 联系我,关注微信公众号:码农每日一题 未经允许严禁转载 https://blog.csdn.net/yanbober】

@RestrictTo(RestrictTo.Scope.LIBRARY)

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;

}

//query、getType、insert、delete、update 实现都是抛出 IllegalStateException(“Not allowed.”);,不再给出。

}

很显然,我们需要将视野挪到的实现源码,AppInitializer 类的代码也就是 App Startup 框架的精华了,如下

public final class AppInitializer {

private static final String SECTION_NAME = “Startup”;

private static volatile AppInitializer sInstance;

private static final Object sLock = new Object();

//已初始化 Initializer 集合

final Map<Class<?>, Object> mInitialized;

//被自动发现的 Initializer 列表

final Set<Class<? extends Initializer<?>>> mDiscovered;

final Context mContext;

AppInitializer(@NonNull Context context) {

mContext = context.getApplicationContext();

mDiscovered = new HashSet<>();

mInitialized = new HashMap<>();

}

@NonNull

@SuppressWarnings(“UnusedReturnValue”)

public static AppInitializer getInstance(@NonNull Context context) {

if (sInstance == null) {

synchronized (sLock) {

if (sInstance == null) {

sInstance = new AppInitializer(context);

}

}

}

return sInstance;

}

@NonNull

public T initializeComponent(@NonNull Class<? extends Initializer> component) {

return doInitialize(component, new HashSet<Class<?>>());

}

public boolean isEagerlyInitialized(@NonNull Class<? extends Initializer<?>> component) {

// If discoverAndInitialize() was never called, then nothing was eagerly initialized.

return mDiscovered.contains(component);

}

@NonNull

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;

//如果这次递归依赖 Initializer 从来没被初始化过,则开始初始化

if (!mInitialized.containsKey(component)) {

//先加入这次递归依赖初始化的临时 set 中

initializing.add(component);

try {

//实例化一个对应的 Initializer 对象

Object instance = component.getDeclaredConstructor().newInstance();

Initializer<?> initializer = (Initializer<?>) instance;

//得到对应的 Initializer 的 dependencies 方法的返回值

List<Class<? extends Initializer<?>>> dependencies =

initializer.dependencies();

//这里没判断 null,所以 Initializer 的 dependencies 方法一定不能返回 null,即便没依赖也得返回一个 emptyList 集合。

if (!dependencies.isEmpty()) {

//遍历当前 Initializer 的 dependencies 依赖 Initializer 列表

for (Class<? extends Initializer<?>> clazz : dependencies) {

//如果依赖的 Initializer 还没有被初始化过,则递归调用初始化

if (!mInitialized.containsKey(clazz)) {

doInitialize(clazz, initializing);

}

}

}

if (StartupLogger.DEBUG) {

为了应付面试也刷了很多的面试题与资料,现在就分享给有需要的读者朋友,资料我只截取出来一部分哦

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

y()) {

//遍历当前 Initializer 的 dependencies 依赖 Initializer 列表

for (Class<? extends Initializer<?>> clazz : dependencies) {

//如果依赖的 Initializer 还没有被初始化过,则递归调用初始化

if (!mInitialized.containsKey(clazz)) {

doInitialize(clazz, initializing);

}

}

}

if (StartupLogger.DEBUG) {

为了应付面试也刷了很多的面试题与资料,现在就分享给有需要的读者朋友,资料我只截取出来一部分哦

[外链图片转存中…(img-TdkHaLPt-1714922181409)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

最新文章
QS排名对网站流量的深远影响
摘要QS排名作为全球大学排名体系之一,对于网站流量有着显著的影响。高质量的内容和良好的用户体验是提升网站流量的关键,而QS排
我的自助建站之路
自助建站的网站和论坛我都尝试过了,这二十天来也接触过虚拟主机。现在说下我从去年开始接触的网络自助建站说起吧!一,自助建网
【头条】裁员800人!又一美企关闭上海等三家工厂;
1.八大创新项目亮相:謇公茶馆科创融资路演专场9月27日即将开幕;2.Vishay宣布重组!裁员800人,关闭上海等三家工厂;3.精美礼品
手机内存严重不足,华为联手雷克沙推出nCARD存储卡,性能实测
本文共2100字,27张图片,预计阅读时间5分钟1、前言2、什么是nCARD3、简单的开箱4、性能测试5、总结前言一年前入手了华为P30 pro
(千年的手游叫什么名字)揭秘千年手游排行榜前十名,畅谈经典游戏排名及魅力
在快节奏的生活中,人们常常寻找一种能够放松身心、享受时光的方式,经典游戏因其独特的魅力和吸引力,成为了许多人闲暇时间的不
2024年Java后端开发学习路线(建议收藏!)
第二部分:Java高级 在Java高级中,我们应该要熟练掌握。Java多线程/高并发,数据结构和算法,设计模式
Android辅助权限的介绍与配置
本文旨在介绍AccessibilityService如果更优雅的使用,以及使用过程遇到的问题,该怎么解决。 辅助功能服务在后台运
CRM客服系统是干啥的?有啥功能、作用和价格?
客服系统的主要功能和作用包括:1、,2、销售自动化,3、营销自动化,4、客户服务,5、数据分析。客户管理是CRM系统的核心功能,
2024精准资料免费|精选解释解析落实
  在信息爆炸的时代,获取高质量的资料成为人们日常生活和工作中不可或缺的一部分。然而,由于互联网的开放性和信息的海量,如