0%

dagger2介绍以及在SystemUI中的应用

一、简介

Dagger2 是主流的依赖注入框架,凭借优秀的性能表现在Android上使用较为广泛,在AOSP源码中也集成了该部分源码,在WORKSPACE/external/dagger2 主要在SystemUI中引用

Dagger 的名字取自有向无环图 DAG (directed acyclic graph),因为程序里的依赖关系拼接起来就是一个或者多个有向无环图。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Heater { //加热器
...
}
class Pump { //泵
private Heater heater;
...
}

class CoffeeMaker {
private Heater heater;
private Pump pump;
//相比在对象内部自己创建,而是交给外部注入
public CofeeMaker(Heater heater, Pump pump) {
this.heater = heater;
this.pump = pump;
}
void brew() {
}
}

对于这个简单的例子来说我们不管是在CoffeeMaker中实例化Heater和Pump 还是手写依赖注入都是非常简单的但是如果一个类有这么多的依赖,并且每个依赖又存在若干个不同的依赖这么组成的一个依赖图,这对我们后期项目的开发以及维护都是一场灾难

1
2
3
4
5
6
7
8
9
10
11
public NotificationPanelViewController(NotificationPanelView view,
@Main Handler handler,
@ShadeDisplayAware LayoutInflater layoutInflater,
FeatureFlags featureFlags,
......此处省略约80
NaturalScrollingSettingObserver naturalScrollingSettingObserver,
MSDLPlayer msdlPlayer,
BrightnessMirrorShowingInteractor brightnessMirrorShowingInteractor) {

....
}

而dagger2的做法是 帮助开发者自动管理依赖并且以一种代码可追踪性的,性能优越的、编译期间可检验正确性的方式

dagger2是通过编译期间生成代码的方式实现依赖注入 如果存在异常会更早点的被检验出,相比其他框架如Spring在运行期间(Spring启动时)通过扫描注解反射的方式创建对象 要有更佳的性能、如果生成了代码如果出错,可以更加简单的追踪到错误位置,并且编译后生成的java文件可以随时查看使用起来更加清晰

二、dagger使用

1、申明依赖

使用@Inject注解位于需要提供依赖的构造方法或者字段上,被@Inject标记的构造方法Dagger将知道该类的构造,当该类被当成依赖被其他类需要时dagger将会执行他的构造方法构造实例 而作为setter或者字段注入的时候则不能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Heater {
...
}
class Pump {


public Heater heater;

@Inject
public Pump(Heater heater) {
this.pump = pump;
}
}

class CoffeeMaker {
private Heater heater;
private Pump pump;

@Inject
public CofeeMaker(Heater heater, Pump pump) {
this.heater = heater;
this.pump = pump;
}
...
}

注意:@Inject不是万能的

  • 接口不能被构造
  • 三方库不能被标记@Inject
  • 可配置对象必须配置好

2、满足依赖关系

根据第一个步骤已经确定了依赖关系,并且由于CoffeMaker和Pump类是用构造方法注入的,也就是说Dagger知道了其构造方法可以构造CoffeMaker和Pump,可是Heater 呢 他们是怎么提供呢?

1
2
3
4
5
6
7
8
9
@Module
abstract class HeaterModule {

@Provider
public static Heater provideHeater() {
return new Heater();
}

}

这里我们假设Heater 已经是叶子节点(没有下一层的依赖),那我们需要为叶子节点注册获取方法告诉dagger 该对象该如何获取,这里我们使用@Provider注解表示该方法将提供一个Heater对象实例,dagger是通过方法的返回值确定依赖类型的

然而实际开发中往往CoffeMaker依赖的不是具体Heater实例,而是Heater接口或抽象类,或者存在多个Heater对象

1
2
3
4
5
6
7
8
9
interface Heater {
...
}
class ElectricHeater implements Heater {
...
}
class GasHeater implements Heater {
...
}

针对这种情况我们如何处理呢?可以看到一下代码,两个方法返回值都是Heater,如果不加以修饰dagger将不知道该获取哪个作为正确依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Module
abstract class HeaterModule {

@Provider @Named("electric")
public static Heater provideElectricHeater() {
return new ElectricHeater();
}

@Provider @Name("gas")
public static Heater provideGasHeater() {
return new GasHeater();
}

}

这里我们假设ElectricHeater GasHeater 是叶子节点,他们共同实现一个接口,为了让dagger区分这两个对象,使用了@Name注解去区分,只需要在获取该依赖的地方同样加上该注解即可获取对应的对象内容后续@Qualifier会提到

public CofeeMaker(@Named("gas") Heater heater, @Name("electric") Pump pump) {

this.heater = heater;

this.pump = pump;

}

然而实际开发过程中情况可能是这样的Pump可能也不止一个,也只能看作一个抽象接口并且Pump他的实例是通过构造方法@Inject标记的,所以他是非叶子节点不能用@Provider去提供接口实例,但是由于我们CoffeeMaker中引用的是Pump接口

1
2
3
4
5
6
7
8
9
10
11
interface Pump {

}
class Thermosiphon implements Pump { // 假设这是非叶子节点
...
}
class ElectricPump implements Pump { // 假设这是非叶子节点
...
@Inject
public ElectricPump (Heater heater) {...}
}

对于以上这种情况我们需要将接口与实例进行绑定 因此可以使用@Binds帮我们实现

1
2
3
4
5
6
7
8
9
10
@Module
abstract class HeaterModule {

@Binds @Named("electric")
abstract Pump bindElectricPump(ElectricPump pump);

@Binds @Name("Thermosiphon")
abstract Pump bindThermosiphon(Thermosiphon pump);

}

我们不论是Binds还是Provider都是写在@Module里面的,作为依赖提供给dagger

这样一来 叶子节点通过@Provider提供 而非叶子节点通过@Inject构造方法提供 另外接口可以由@Binds进行绑定,那么层层依赖关系就全部缕清楚咯

3、构建对象图

@Inject@Provides 标记的类,会自动拼成一张“依赖关系图”,里面的对象根据需要互相连接起来。那应用程序要怎么用这张图呢?通常就是在入口地方,比如 main 方法或者 Android 的 Application定义一个明确的接口,去拿到里面的对象。

在 Dagger 2 里,你要先定义一个接口,这个接口里写一些没参数、直接返回你想要对象的方法。然后你给这个接口加上 @Component 注解,并把需要用到的模块(modules)传进去。Dagger 2 就会帮你生成一个实现这个接口的类,自动把所有依赖都装配好。

这样说起来就像:你只要列个清单(接口),告诉 Dagger “我要这些东西”,它就会帮你把背后复杂的依赖链都串起来,然后直接交给你。

1
2
3
4
5
6
7
8
9
@Component(modules = HeaterModule.class)
interface CoffeeShop {

@Component.Builder
interface builder{
CoffeShop build();
}
CoffeeMaker maker();
}

编译过后dagger将帮你自动生成一个类:DaggerCoffeeShop.java作为Component实例 并且根据已经申明好了的依赖和满足好的依赖关系自动帮你实现了maker()方法

我们可以在需要使用CoffeeMaker的地方调用

CoffeeShop coffeeShop = DaggerCoffeeShop.Builder.build();

1
CoffeMaker maker = coffeeShop.maker();

即可获取到CoffeMaker的实例,通常我们使用dagger框架时,会在程序的起点main函数或者Anndroid中 Application里面获取到顶层的Component实例,通过这个实例获取我们需要的实例如:SystemUI启动后通过Dagger实例化他的组件服务以及他们的依赖(以及依赖的依赖),实例化好后开启服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
编译产物
@DaggerGenerated
@Generated(
value = "dagger.internal.codegen.ComponentProcessor",
comments = "https://dagger.dev"
)
@SuppressWarnings({
"unchecked",
"rawtypes",
"KotlinInternal",
"KotlinInternalInJava",
"cast",
"deprecation",
"nullness:initialization.field.uninitialized"
})
public final class DaggerCoffeeShop {
private DaggerCoffeeShop() {
}

public static CoffeeShop.Builder builder() {
return new Builder();
}

public static CoffeeShop create() {
return new Builder().build();
}

private static final class Builder implements CoffeeShop.Builder {
@Override
public CoffeeShop build() {
return new CoffeeShopImpl();
}
}

private static final class CoffeeShopImpl implements CoffeeShop {
private final CoffeeShopImpl coffeeShopImpl = this;

private CoffeeShopImpl() {


}

private ElectricPump electricPump() {
return new ElectricPump(HeaterModule_ProvideElectricHeaterFactory.provideElectricHeater());
}

@Override
public CoffeeMaker maker() {
return new CoffeeMaker(HeaterModule_ProvideElectricHeaterFactory.provideElectricHeater(), electricPump());
}
}
}

4、完善作用域

注解@Provider的方法每次被执行都会产生不同的对象,有时候我们需要在不同类中依赖同一个对象,如

1
2
CoffeShop`依赖 `Heater
Pump` 依赖 `Heater

我们通常希望两者依赖的Heater是同一个对象,可以使用@Singleton注解解决此问题,加上该注解可以保持Component级别的单例(只要Component不变获取到的实例及是不变的)

1
2
3
4
5
@Component(modules = DripCoffeeModule.class)
@Singleton
interface CoffeeShop {
CoffeeMaker maker();
}

将@Singleton定义在Component接口上表示该Component的作用域是@Singleton,看上去非常的令人迷惑听上去也是,但是不着急我们慢慢看

1
2
3
4
5
6
7
8
@Module
abstract class HeaterModule {
@Provider
@ActivityScope // 在此处+ @Singleton
public static Heater provideElectricHeater() {
return new ElectricHeater();
}
}

表示Heater的作用域在@SingletonCoffeShop是相同作用域,于是Heater在实例化过一次后将会缓存在这个作用域,如果该作用域还有其他的类依赖该Heater,直接命中缓存,通过这样的方式在相同作用域里面实现单例,

通过阅读Singleton定义可以的出@Singleton只是一个特殊的@Scope,我们也可以自定义一些Scope代表一些含义

1
2
3
4
@Scope
@Documented
@Retention(RUNTIME)
public @interface ActivityScope {}

比如定义一个ActivityScope 将其描述于一个子Component(@Subcomponent)中,该Component我们交由Activity管理在onCreate时获取,onDestroy时销毁,那在此期间可以保持单例。一旦Activity销毁重建Component也将重新生成,将在下一个周期保持不变但与上一个周期不同,实现在Activity级别的单例,同理交给Application管理可以实现app级别单例

5、子组件(子图)

子组件是继承并扩展父组件对象图的组件。你可以使用子组件把应用的对象图拆分成更小的子图:

  • 一方面可以让应用的不同部分彼此隔离;
  • 另一方面也可以在同一个组件体系里使用多个不同的作用域(scope)。

在子组件中绑定的对象,可以依赖:

  • 父组件或任何祖先组件里绑定的对象,
  • 以及子组件自己模块中绑定的对象。

但是反过来不行:

  • 父组件里的对象 不能依赖 子组件里的对象;
  • 一个子组件里的对象 也不能依赖 另一个“兄弟”子组件里的对象。

换句话说:

父组件的对象图,其实只是子组件对象图的一个子集。

声明子组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//ReferenceSysUIComponent.java
@SysUISingleton
@Subcomponent(modules = {
DefaultComponentBinder.class,
...
ReferenceSystemUIModule.class})
public interface ReferenceSysUIComponent extends SysUIComponent {

@SysUISingleton
@Subcomponent.Builder
interface Builder extends SysUIComponent.Builder {
ReferenceSysUIComponent build();
}

void inject(CustomizationProvider customizationProvider);
}

//ReferenceGlobalRootComponent.java
@Singleton
@Component(modules = {GlobalModule.class})
public interface ReferenceGlobalRootComponent extends GlobalRootComponent {

/**
* Builder for a ReferenceGlobalRootComponent.
*/
@Component.Builder
interface Builder extends GlobalRootComponent.Builder {
ReferenceGlobalRootComponent build();
}

/**
* Builder for a {@link ReferenceSysUIComponent}, which makes it a subcomponent of this class.
*/
ReferenceSysUIComponent.Builder getSysUIComponent(); //通过获取副组件构造器的方式确定父子关系
}

子组件理由

为了使用作用域(scope)

举个例子:在使用Scope后依赖都是单例的,但是有时候我希望在Activity销毁重建后能得到一个新的对象, 比如登陆表单的时候,每次输入错误表单界面会有错误状态、提示信息等等,我希望重新进入页面时候是一个全新的表单而不是原来那个带有错误状态的,就可以将该部分依赖移动至Subomponent,定义一个新的Scope

用子组件做封装

使用子组件的另一个原因,是为了让应用的不同部分彼此隔离。

例如,服务器里的两个服务(或应用中的两个界面)可能共享一些绑定(如认证、授权),但各自又有独立绑定。这时可以为每个服务或界面创建单独的子组件,把共享的绑定放到父组件里

6、多重绑定

Dagger 允许你将多个对象绑定到一个集合中,即使这些对象绑定在不同的模块中,这称为 multibindings(多重绑定)。Dagger 会组装这个集合,使应用程序代码可以注入它,而不需要直接依赖各个单独的绑定。

你可以使用 multibindings 来实现插件架构,例如,多个模块可以贡献各自的插件接口实现,然后中央类可以使用所有插件。或者,你可以让多个模块贡献单独的服务提供者到一个 map 中,以名字作为 key。

SystemUI中的组件服务就是这个架构

Map绑定

Dagger 允许你向可注入的 map 贡献条目,只要 map 的 key 在编译时已知。

向多重绑定 map 贡献一个条目,在模块方法上返回值并加上 @IntoMap 注解,同时使用一个自定义注解指定 map key。Key 必须唯一,如果 map 内有重复 key,会报编译错误。带限定符的 map 条目需要在每个 @IntoMap 方法上加上限定符。

然后你可以注入 map 本身 (Map<K, V>) 或带 value provider 的 map (Map<K, Provider>)。后一种方式有用,例如不希望立即实例化所有值(懒加载),或者想处理 Provider 异常,或者每次查询都得到新实例。

Interface Provider {

​ T get();

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Module(
includes = [
...
WallpaperModule::class,
]
)
abstract class SystemUICoreStartableModule {
/** Inject into BiometricNotificationService */
@Binds
@IntoMap
@ClassKey(BiometricNotificationService::class)
abstract fun bindBiometricNotificationService(
service: BiometricNotificationService //实例由构造Inject提供
): CoreStartable

/** Inject into ClipboardListener. */
@Binds
@IntoMap
@ClassKey(ClipboardListener::class)
abstract fun bindClipboardListener(sysui: ClipboardListener): CoreStartable

/** Inject into GlobalActionsComponent. */
@Binds
@IntoMap
@ClassKey(GlobalActionsComponent::class)
abstract fun bindGlobalActionsComponent(sysui: GlobalActionsComponent): CoreStartable
}

获取的同样在Component中

1
2
3
4
5
6
7
8
9
10
11
12
13
@SysUISingleton
@Subcomponent(modules = {
...
SystemUICoreStartableModule.class,
...)
public interface SysUIComponent {

......

Map<Class<?>, Provider<CoreStartable>> getStartables();

......
}

编译后真实情况:

1
2
3
4
5
6
7
8
9
10
//编译后
public Map<Class<?>, javax.inject.Provider<CoreStartable>> getStartables() {
return MapBuilder.newMapBuilder(109)
.put(NotificationLogger.class, this.provideCoreStartableProvider)
.put(ShortcutHelperActivityStarter.class, this.starterProvider)
.put(ShortcutHelperRepository.class, this.repoProvider)
.........
.put(BroadcastDispatcherStartable.class, this.broadcastDispatcherStartableProvider)
.put(Recents.class, this.volumeUIProvider).build();
}

后续可以通过该Map在开机后一次性启动组件服务

1
2
3
4
@Binds
@IntoMap
@ClassKey(ForegroundServicesDialog.class)
public abstract Activity bindForegroundServicesDialog(ForegroundServicesDialog activity);

還可以將Activity Service Broadcast ContentProvider 四大組件綁定到Map中,由于四大组件实例化过程在系统端而非应用端所以一般来说无法在他们其中通过构造方法实现依赖注入,可以通过这种方式配合AppComponentFactory实现在四大组件的构造器中注入依赖

7、其他

外部绑定实例

绑定实例到Component中,可以在后续依赖注入时直接使用

比如在其他地方想注入主线程Handler方便执行主线程操作,但是Handler的获取要通过Context获得,而Context由App启动时Application才初始化好,所以dagger只能在构建对象图时获取

1
2
3
4
5
6
7
8
9
10
11
12
13
public interface GlobalRootComponent {

/**
* Builder for a GlobalRootComponent.
*/
interface Builder {
@BindsInstance
Builder context(Context context); //绑定Context到依赖库
@BindsInstance
Builder instrumentationTest(@InstrumentationTest boolean test);
GlobalRootComponent build();
}
}

同个类型多个不同实例

定义于注解上区分相同类型的不同依赖。比如需要注入两个Executor 分别代表着主线程以及后台线程可以这样做:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
//Main.java
@Qualifier
@Documented
@Retention(RUNTIME)
public @interface Main {
}
//Background.java
@Qualifier
@Documented
@Retention(RUNTIME)
public @interface Background {
}


//GlobalConcurrencyModule.java
@Provides
@Singleton
@Main
public static Executor provideMainExecutor(Context context) {
return context.getMainExecutor();
}
//SysUIConcurrencyModule.kt

@Provides
@SysUISingleton
@Background
fun provideBackgroundExecutor(@Background looper: Looper): Executor = ExecutorImpl(looper)



//DreamOverlayStatusBarItemsProvider.java
@Inject
public DreamOverlayStatusBarItemsProvider(@Main Executor executor) {
mExecutor = executor;
}
//ObservableServiceConnection.java
@Inject
public ObservableServiceConnection(Context context, Intent serviceIntent,
UserTracker userTracker,
@Background Executor bgExecutor,
ServiceTransformer<T> transformer) {
...
mBgExecutor = bgExecutor;
...
}

@Named

自身由Qualifier定义,作用与Qualifier一致

1
2
3
4
5
6
7
8
@Qualifier
@Documented
@Retention(RUNTIME)
public @interface Named {

/** The name. */
String value() default "";
}

辅助注入

用于构造对象时,部分参数由 DI 框架提供,而其他参数必须在创建时由用户传入(半自动管理)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@AssistedInject //声明这是一个辅助注入类型
public DelayedWakeLock(@Background Lazy<Handler> bgHandler,
@Main Lazy<Handler> mainHandler,
Context context, WakeLockLogger logger,
@Assisted String tag) { // 声明该参数由用户传入
mInner = WakeLock.createPartial(context, logger, tag);
mHandler = Flags.delayedWakelockReleaseOnBackgroundThread() ? bgHandler.get()
: mainHandler.get();
}
...
@AssistedFactory //声明助理工厂,编译中DelayedWakeLock的构造方法根据自动生成动态依赖String tag的方法
public interface Factory {
/** creates the instance of DelayedWakeLock class. */
DelayedWakeLock create(String tag);
}

相当于DelayedWakeLock注入到DelayedWakeLock.Factory中,其他地方需要使用DelayedWakeLock,通过注入该工厂获取即可

@Inject DelayedWakeLock.Factory delayedWakeLockFactory; // 工厂通过Inject获取依赖

1
DelayedWakeLock wakelock = delayedWakeLockFactory.create("Scrims"); 

三、查看SystemUI中的依赖注入流程

SystemUI启动流程

SystemUIService 是在SystemUI app 中的一个 Service ,要启动Service 先会实例化SystemUIApplication

Application的代理实例化

由于Application的实例化过程是在系统端,为了获取Application实例化的控制权使用AppComponentFactory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//SystemUIAppComponentFactoryBase.kt  --> AppComponentFactory.java

override fun instantiateApplicationCompat(cl: ClassLoader, className: String): Application {
val app = super.instantiateApplicationCompat(cl, className)
if (app !is ContextInitializer) {
throw RuntimeException("App must implement ContextInitializer")
} else {
app.setContextAvailableCallback { context -> //设置一个在onCreate方法中执行的回回调函数
createSystemUIInitializerInternal(context)
}
}
return app
}

private fun createSystemUIInitializerInternal(context: Context): SystemUIInitializer {
return systemUIInitializer ?: run {
val initializer = createSystemUIInitializer(context.applicationContext)
try {
initializer.init(false) // 重点在这
} catch (exception: ExecutionException) {
throw RuntimeException("Failed to initialize SysUI", exception)
} catch (exception: InterruptedException) {
throw RuntimeException("Failed to initialize SysUI", exception)
}
initializer.sysUIComponent.inject(
this@SystemUIAppComponentFactoryBase
)

systemUIInitializer = initializer
return initializer
}
}

AppComponentFactory 是实例化 Application 、 Activity 、Service 、ContentProvicder 、BroadcastReceiver的工厂,系统在实例化四大组件以及Application时是交由他去实例化的、我们可以自行实现该类并且注册至Manifest中,在系统实例化以上类的时候会替换到自定义的工厂

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
//SystemUIInitializer.java

public void init(boolean fromTest) throws ExecutionException, InterruptedException {
mRootComponent = getGlobalRootComponentBuilder()
.context(mContext)
.instrumentationTest(fromTest)
.build();

mInitializationChecker = mRootComponent.getInitializationChecker();
boolean initializeComponents = mInitializationChecker.initializeComponents();

// Stand up WMComponent
setupWmComponent(mContext); // 初始化 mWMComponent

// And finally, retrieve whatever SysUI needs from WMShell and build SysUI.
SysUIComponent.Builder builder = mRootComponent.getSysUIComponent();
// 将WMShell 模块核心依赖添加到 ApplicationSingeton scope中
if (initializeComponents) {
// Only initialize when not starting from tests since this currently initializes some
// components that shouldn't be run in the test environment
builder = prepareSysUIComponentBuilder(builder, mWMComponent)
.setShell(mWMComponent.getShell())
.setPip(mWMComponent.getPip())
.setSplitScreen(mWMComponent.getSplitScreen())
.setOneHanded(mWMComponent.getOneHanded())
.setBubbles(mWMComponent.getBubbles())
.setTaskViewFactory(mWMComponent.getTaskViewFactory())
.setShellTransitions(mWMComponent.getShellTransitions())
.setKeyguardTransitions(mWMComponent.getKeyguardTransitions())
.setStartingSurface(mWMComponent.getStartingSurface())
.setDisplayAreaHelper(mWMComponent.getDisplayAreaHelper())
.setRecentTasks(mWMComponent.getRecentTasks())
.setBackAnimation(mWMComponent.getBackAnimation())
.setDesktopMode(mWMComponent.getDesktopMode());

// Only initialize when not starting from tests since this currently initializes some
// components that shouldn't be run in the test environment
mWMComponent.init();
} else {
......
}
mSysUIComponent = builder.build(); // 实例化Component,(生成依赖关系图)

// Every other part of our codebase currently relies on Dependency, so we
// really need to ensure the Dependency gets initialized early on.
Dependency dependency = mSysUIComponent.createDependency();
dependency.start(); // 初始化全局仓库
}

Application初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//SystemUIApplication.java

@Override
public void onCreate() {
super.onCreate();

mInitializer = mContextAvailableCallback.onContextAvailable(this); // 初始化Component
//获取子组件Component scope: @SysUISingleton
mSysUIComponent = mInitializer.getSysUIComponent();
mBootCompleteCache = mSysUIComponent.provideBootCacheImpl();
log.traceEnd();
//获取根组件Component scope: @Singleton
GlobalRootComponent rootComponent = mInitializer.getRootComponent();

// Enable Looper trace points.
// This allows us to see Handler callbacks on traces.
......
}

启动SystemUIService

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//SystemUIService.java
@Override
public void onCreate() {
super.onCreate();

// Start all of SystemUI
((SystemUIApplication) getApplication()).startSystemUserServicesIfNeeded();

......
}

//SystemUIApplication

public void startSystemUserServicesIfNeeded() {
if (!shouldStartSystemUserServices()) {
Log.wtf(TAG, "Tried starting SystemUser services on non-SystemUser");
return; // Per-user startables are handled in #startSystemUserServicesIfNeeded.
}
final String vendorComponent = mInitializer.getVendorComponent(getResources());

// Sort the startables so that we get a deterministic ordering.
// TODO: make #start idempotent and require users of CoreStartable to call it.
Map<Class<?>, Provider<CoreStartable>> sortedStartables = new TreeMap<>(
Comparator.comparing(Class::getName));
sortedStartables.putAll(mSysUIComponent.getStartables()); // 获取所有Corestartabe
sortedStartables.putAll(mSysUIComponent.getPerUserStartables());
startServicesIfNeeded(
sortedStartables, "StartServices", vendorComponent); //启动服务的核心方法
}

小而美的Corestartable组件服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public interface CoreStartable extends Dumpable {
String STARTABLE_DEPENDENCIES = "startable_dependencies";

/** Main entry point for implementations. Called shortly after SysUI startup. */
void start();

@Override
default void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
}

/** Called to determine if the dumpable should be registered as critical or normal priority */
default boolean isDumpCritical() {
return true;
}

/** Called immediately after the system broadcasts
* {@link android.content.Intent#ACTION_LOCKED_BOOT_COMPLETED} or during SysUI startup if the
* property {@code sys.boot_completed} is already set to 1. The latter typically occurs when
* starting a new SysUI instance, such as when starting SysUI for a secondary user.
* {@link #onBootCompleted()} will never be called before {@link #start()}. */
default void onBootCompleted() {
}
}

SystemUI的每个组件服务都是一个小巧的CoreStartable接口,启动服务就是执行其中的start()方法即可并非Android四大组件中的Service,或许将来你编写的一个SystemUI的功能也可以作为服务的形式添加到SystemUI中

我们知道服务就是一个个CoreStartable的实例,自然我们需要实例化他们,他们的依赖由dagger提供,举例分析:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@SysUISingleton
public class KeyguardUpdateMonitor implements TrustManager.TrustListener, CoreStartable {

@Inject
protected KeyguardUpdateMonitor(
Context context,
UserTracker userTracker,
@Main Looper mainLooper,
BroadcastDispatcher broadcastDispatcher, // 以这个类为例
DumpManager dumpManager,
@Background Executor backgroundExecutor,
@Main Executor mainExecutor,
StatusBarStateController statusBarStateController,
LockPatternUtils lockPatternUtils,
AuthController authController,
......
}
}
1
2
3
4
5
6
7
8
9
10
11
@SysUISingleton
open class BroadcastDispatcher @Inject constructor(
private val context: Context,
@Main private val mainExecutor: Executor,
@BroadcastRunning private val broadcastLooper: Looper,
@BroadcastRunning private val broadcastExecutor: Executor,
private val dumpManager: DumpManager,
private val logger: BroadcastDispatcherLogger,
private val userTracker: UserTracker,
private val removalPendingStore: PendingRemovalStore
) : Dumpable {

在启动Corestartable前将会先实例化,在实例化过程中由dagger

打个比方,如果你是一个电脑生产工厂那么dagger就是你的工厂助理

1、如果你需要生产一台电脑,那么你将大致需要(依赖) CPU 内存 硬盘 主板 显卡 等等,你将这些依赖需求告知dagger

2、dagger如果有现成的这些配件那么将会直接利用起来(命中缓存) 如果没有还需要分别生产

3、我们简单的以显卡为例,显卡生产又需要(依赖) 核心 显存 PCB版 等等 dagger将重复第2步找得到依赖项的依赖直到为最初加工品或者命中缓存, 这样dagger助理就帮我们完成了复杂的依赖传递

结果就是dagger将为你生产CPU 内存 硬盘 主板 显卡 等等 并交给你完成一台电脑的生产