在上一篇文章中,介绍了SystemUI的启动流程,并且简单提及了Dagger2用来管理各个SystemUI中要用的依赖。而这部分代码就在:mContextAvailableCallback.onContextAvailable(this);流程中。而这部分流程我们只是一笔带过,并没有仔细分析。
接下来将会从这个调用开始,介绍SystemUI中Component,subcomponent的初始化,并理解应该怎么使用这些Component。
本文会先以一个例子,简单引入Dagger2中对各个注解的生成模板,然后在介绍SystemUI中重要component和subcomponent的创建过程,最后过渡到一个关键的类Dependency
注意:此处之所以另起一个例子来说明Dagger2的生成模板,完全是因为Dagger2对SystemUI的生成代码太多,导致不太好列成文档
为了能够更好理解Dagger2的生成代码的模板,我们按照如下的例子进行编写,然后查看生成的类.
将下面的代码放入一个DemoComponent.java的文件中
//最顶层的Component,其有两个模块,分别为:
// DemoSubComponent1.DemoModule1
// DemoSubComponent2.DemoModule2
//最顶层Component,提供两个接口,用于得到SubComponent的Factory和Builder类
@Component(modules = {DemoSubComponent1.DemoModule1.class,
DemoSubComponent2.DemoModule2.class})
public interface DemoComponent {
DemoSubComponent1.Factory getSubComponent1Factory();
DemoSubComponent2.Builder getSubComponent2Builder();
}
//SubComponent1,提供如下两个功能
// 1. 获得DemoAClass对象
// 2. 向DemoInject对象中,注入需要的对象
@SysUISingleton
@Subcomponent
interface DemoSubComponent1{
@Subcomponent.Factory
interface Factory {
DemoSubComponent1 create();
}
DemoAClass getAClass();
void inject(DemoInject inject);
//SubComponent1隶属于的模块
//指定了DemoInterface 和DemoBinds之间的关系,当需要DemoInterface的时候,
// Dagger2会创建对应的DemoBinds对象
@Module(subcomponents = DemoSubComponent1.class)
abstract class DemoModule1{
@Binds
abstract DemoInterface getInterface(DemoBinds bindings);
}
}
//SubComponent2,提供一个功能
// 1. 获取DemoBClass对象
@Subcomponent
interface DemoSubComponent2{
//为了和SubComponent1作区分,这里使用了Builder类来创建SubComponent2
@Subcomponent.Builder
interface Builder {
DemoSubComponent2 build();
}
DemoBClass getBClass();
//SubComponent2隶属的模块,该模块还提供了一个@Provides
@Module(subcomponents = DemoSubComponent2.class)
class DemoModule2{
//当需要DemoProvider对象的时候,就会调用此方法
@Provides
DemoProvider getProvider(){
return new DemoProvider();
}
}
}
//用于演示@Binds
interface DemoInterface{
void test();
}
//用于演示@Binds
class DemoBinds implements DemoInterface{
@Inject
DemoBinds(){
}
@Override
public void test() {
}
}
//用于演示@Provides
class DemoProvider{
}
//用于演示,inject函数
class DemoInject{
@Inject
DemoAClass a;
}
//用于演示,生命周期
@SysUISingleton
class DemoAClass{
@Inject
public DemoAClass(){
}
}
//用于演示返回的对象
class DemoBClass{
@Inject
public DemoBClass(){
}
}
有了上面所画的图,接下来查看,Dagger2根据图生成的文件,生成的文件有:
接下来我们挨个查看生成的7个文件,分别是什么内容,DaggerDemoComponent.java中会使用剩下的6个类。因此,我们先看剩下的6个类,最后再查看DaggerDemoFactory.java
DemoAClass_Factory的源码如下:
//对于任何类来讲,只要其构造函数带有@Inject,则Dagger2都会创建一个对应的工厂类,
//叫做:XXX_Factory,它实现了Factory接口
//欲使用这个工厂类,则调用create()方法,得到这个工厂类的实例,工厂类的实例永远只有一个
//欲使用这个工厂类产生的对象,则调用newInstance()方法,得到工厂类的产生对象,
//工厂类产生的对象可以有多个
public final class DemoAClass_Factory implements Factory<DemoAClass> {
@Override
public DemoAClass get() {
return newInstance();
}
public static DemoAClass_Factory create() {
return InstanceHolder.INSTANCE;
}
public static DemoAClass newInstance() {
return new DemoAClass();
}
//用于缓存工厂类实例
private static final class InstanceHolder {
private static final DemoAClass_Factory INSTANCE = new DemoAClass_Factory();
}
}
DemoBClass_Factory,DemoBinds_Factory同DemoAClass_Factory一模一样,不再啰嗦。
DemoInject_MembersInjector用于辅助成员的注入,因为在DemoInject类中如下的代码
class DemoInject{
@Inject
DemoAClass a;
}
整个辅助类源码如下:
//每一个辅助注入的类,都是MembersInjector的具体实现
//在实现中,对要注入的成员,使用Provider表示,抽象为:T的提供者。它会在辅助类创建的时候被
//初始化好
// 对被注入的类,使用instance表示
//同工厂类一样,辅助注入类的实例化,也是通过create()方法进行
//同工厂类不一样的是,每次create,都会创建不同的辅助注入对象
//注入方式,则直接调用injectMembers()函数进行
public final class DemoInject_MembersInjector implements MembersInjector<DemoInject> {
private final Provider<DemoAClass> aProvider;
public DemoInject_MembersInjector(Provider<DemoAClass> aProvider) {
this.aProvider = aProvider;
}
public static MembersInjector<DemoInject> create(Provider<DemoAClass> aProvider) {
return new DemoInject_MembersInjector(aProvider);
}
@Override
public void injectMembers(DemoInject instance) {
injectA(instance, aProvider.get());
}
@InjectedFieldSignature("com.android.systemui.dagger.DemoInject.a")
public static void injectA(Object instance, Object a) {
((DemoInject) instance).a = (DemoAClass) a;
}
}
上面的辅助注入类也很简单,接着往下看
DemoSubComponent2_DemoModule2_GetProviderFactory类表示的是对@Provides的实现工厂类,源码如下:
//对于任何一个被@Provides标记的函数,Dagger2都会创建一个提供者工厂类,它实现了Factory
//同DemoAClass工厂类一样,它也会有一个create()方法,用于实例化提供者工厂类
//不同之处在于,每次调用都会创建一个新的提供者工厂类
//只有需要提供者工厂类,生产提供者时,才会调用get()方法,用于返回生产出来的对象。
public final class DemoSubComponent2_DemoModule2_GetProviderFactory implements Factory<DemoProvider> {
private final DemoSubComponent2.DemoModule2 module;
public DemoSubComponent2_DemoModule2_GetProviderFactory(DemoSubComponent2.DemoModule2 module) {
this.module = module;
}
@Override
public DemoProvider get() {
return getProvider(module);
}
public static DemoSubComponent2_DemoModule2_GetProviderFactory create(
DemoSubComponent2.DemoModule2 module) {
return new DemoSubComponent2_DemoModule2_GetProviderFactory(module);
}
public static DemoProvider getProvider(DemoSubComponent2.DemoModule2 instance) {
return Preconditions.checkNotNullFromProvides(instance.getProvider());
}
}
上面的代码,依然很简单,不再啰嗦
DemoSubComponent2_DemoModule2_Proxy是对抽象模块的表示,源码如下:
public final class DemoSubComponent2_DemoModule2_Proxy {
private DemoSubComponent2_DemoModule2_Proxy() {
}
public static DemoSubComponent2.DemoModule2 newInstance() {
return new DemoSubComponent2.DemoModule2();
}
}
在DemoModule2中,没有任何需要实现的地方,且@Binds已经语义足够明显,所以上面生成的类,没有任何过多的地方。较简单
接下来,就是看看DaggerDemoComponent如何使用上面创建的类来处理他们之间的依赖关系
DaggerDemoComponent是整个依赖注入的入口,其源码如下:
//实现我们的DemoComponent接口,其命名为DaggerAAA_BBB。其中下划线后面的名字,为内部类的名字
public final class DaggerDemoComponent implements DemoComponent {
private DaggerDemoComponent() {
}
//builder()方法和create()方法,都是为了创建DaggerDemoComponent的实例
public static Builder builder() {
return new Builder();
}
public static DemoComponent create() {
//委托给Builder类创建
return new Builder().build();
}
//返回subcomponent1的Factory类,用于创建subcomponent1
@Override
public DemoSubComponent1.Factory getSubComponent1Factory() {
//见后文
return new DemoSubComponent1Factory();
}
//返回subcomponent2的Bulder类,用于创建subcomponent2
@Override
public DemoSubComponent2.Builder getSubComponent2Builder() {
return new DemoSubComponent2Builder();
}
//用于创建DaggerDemoComponent,在这个类中,只是简单的new了一个DaggerDemoComponent即可
public static final class Builder {
private Builder() {
}
@Deprecated
public Builder demoModule2(DemoSubComponent2.DemoModule2 demoModule2) {
Preconditions.checkNotNull(demoModule2);
return this;
}
public DemoComponent build() {
return new DaggerDemoComponent();
}
}
//实现DemoSubComponent1的Factory接口,该接口提供create()方法来创建对应的实例
private final class DemoSubComponent1Factory implements DemoSubComponent1.Factory {
@Override
public DemoSubComponent1 create() {
//创建DemoSubComponent1的实例对象,并返回
return new DemoSubComponent1Impl();
}
}
//subcomponet1的具体实现
private final class DemoSubComponent1Impl implements DemoSubComponent1 {
private Provider<DemoAClass> demoAClassProvider;
private DemoSubComponent1Impl() {
initialize();
}
//辅助构造函数,对DemoAClass的提供者,进行初始化
//因为我们将DemoAClass的生命周期和DemoSubComponent1的生命周期,都标记为
//@SysUISingleton
//所以他们同生同死,为了达到这个效果,需要在subcomponent1中持有对DemoAClass的提供者,
//而不是每次重新创建(对比下面的getBClass()函数)
//这样,在需要DemoAClass的地方(如getAClass()函数),就直接让提供者来提供,而提供者保证了
//每次都提供同一个对象
//DemoAClass的提供者,我们首先想到的就是,前面介绍过的DemoAClass_Factory工厂类,
//调用其newInstance()
//就会创建一个DemoAClass对象。但是它并不能保证每次提供同一个对象,因此再次对
//DemoAClass_Factory进行封装
//这个封装就是DoubleCheck对象,它保证了每次提供同一个对象,同时也保证了线程安全
//DoubleCheck最终也会使用DemoAClass_Factory类来实例化DemoAClass对象
@SuppressWarnings("unchecked")
private void initialize() {
this.demoAClassProvider = DoubleCheck.provider(DemoAClass_Factory.create());
}
//调用DemoAClass的提供者,让其提供同一个对象
@Override
public DemoAClass getAClass() {
return demoAClassProvider.get();
}
//向DemoInject中注入需要的成员
@Override
public void inject(DemoInject inject) {
injectDemoInject(inject);
}
//调用对应的辅助注入类,注入需要的成员
private DemoInject injectDemoInject(DemoInject instance) {
DemoInject_MembersInjector.injectA(instance, demoAClassProvider.get());
return instance;
}
}
//subcomponnet2的Builder接口实现
private final class DemoSubComponent2Builder implements DemoSubComponent2.Builder {
@Override
public DemoSubComponent2 build() {
//创建subcomponent2对象,并直接返回
return new DemoSubComponent2Impl();
}
}
//subcomponent2的具体实现类
private final class DemoSubComponent2Impl implements DemoSubComponent2 {
//因为DemoSubComponent2和DemoBClass并不是同一生命周期,所以,每次都创建一个新的
//DemoBClass对象返回
//因此,也就不需要相应的提供者类,也就不需要相应的对提供者类进行初始化
private DemoSubComponent2Impl() {
}
@Override
public DemoBClass getBClass() {
return new DemoBClass();
}
}
}
在Component中完成了如下的工作:
至此,我们对Dagger2生成的模板有了一个整体把握,并对其中的实现细节,做了一些注释说明。
接下来我们继续看看SystemUI中的重要组件的创建过程
第一篇文章,我们一笔带过了SystemUIApplication.onCreate()中的mContextAvailableCallback.onContextAvailable(this).
这就是Dagger2创建依赖的起点,mContextAvailableCallback的赋值,在SystemUIAppComponentFactory.java中。
如下:
@NonNull
@Override
//此函数在创建SystemUIApplication之前调用
public Application instantiateApplicationCompat(
@NonNull ClassLoader cl, @NonNull String className)
throws InstantiationException, IllegalAccessException, ClassNotFoundException {
//调用父类方法,创建Application,此处的app实例为SystemUIApplication
Application app = super.instantiateApplicationCompat(cl, className);
if (app instanceof ContextInitializer) {
//给SystemUIApplication的mContextAvailableCallback赋值
((ContextInitializer) app).setContextAvailableCallback(
context -> {
//SystemUIApplication的onCreate处开始调用
//1. 首先创建SystemUIFactory(SystemUIFactory会负责创建各种依赖)
//2. 然后马上注入SystemUIAppComponentFactory所需的成员(即
// ContextComponentHelper)
SystemUIFactory.createFromConfig(context);
SystemUIFactory.getInstance().getSysUIComponent().inject(
SystemUIAppComponentFactory.this);
}
);
}
return app;
}
从上面我们看见了SystemUIFactory调用静态方法createFromConfig进行创建。从名字也能猜测一二:从配置中创建SystemUIFactory
唉,这个就值得思考了,为何要从配置中创建?难道可以配置成不同的SytemUIFactory吗?每个SystemUIFactory有什么区别吗?
我们带着问题往下看
SystemUIFactory从名字上,似乎是SystemUI的工厂类。在上一篇文章Android 12 源码分析 —— 应用层 二(SystemUI大体组织和启动过程):http://t.csdn.cn/AuzsL的自定义组件小节中,我们自定以的组件继承了SystemUI
难道SystemUIFactory是它的工厂类?
我们来看看源码,为了减少干扰,我们从上一小节中的createFromConfig方法开始查看,如下
public static void createFromConfig(Context context) {
createFromConfig(context, false);
}
@VisibleForTesting
//最终调用的地方
public static void createFromConfig(Context context, boolean fromTest) {
//1. 如果SystemUIFactory,即mFactory,已经存在,则什么也不做
if (mFactory != null) {
return;
}
//2. 倘若1不满足,则读取配置文件中的类名,然后使用反射创建这个对象
//config_systemUIFactoryComponent的值即为com.android.systemui.SystemUIFactory
//那么请思考,是不是还有另外的类名,事实上是有的,还可以为:
//com.android.systemui.tv.TvSystemUIFactory.我们后面来比较他们之间的区别
final String clsName = context.getString(R.string.config_systemUIFactoryComponent);
if (clsName == null || clsName.length() == 0) {
throw new RuntimeException("No SystemUIFactory component configured");
}
//3. 创建完成对象之后,则调用init方法
try {
Class<?> cls = null;
cls = context.getClassLoader().loadClass(clsName);
mFactory = (SystemUIFactory) cls.newInstance();
mFactory.init(context, fromTest);
} catch (Throwable t) {
Log.w(TAG, "Error creating SystemUIFactory component: " + clsName, t);
throw new RuntimeException(t);
}
}
接下来,继续进入其初始化函数中,如下:
@VisibleForTesting
public void init(Context context, boolean fromTest)
throws ExecutionException, InterruptedException {
//是否要运行初始化的一个判断,全部满足下面的条件则初始化
//1. 非测试模块运行
//2. 是主用户
//3. 是主进程
mInitializeComponents = !fromTest
&& android.os.Process.myUserHandle().isSystem()
&& ActivityThread.currentProcessName().equals(ActivityThread.currentPackageName());
//又见GlobalRootComponent。在上一篇文章中已经提及过
//这里就是去构建整个应用最最顶层的那个Component
mRootComponent = buildGlobalRootComponent(context);
//从GlobalRootComponent中,获取需要创建依赖的Builder。然后创建依赖
//1. 先创建WmComponent (这是一个与SysUIComponent站在同一维度的Component,它负责提供WindowManager相关的东西,此处可不用太过在意,后面会详解)
mWMComponent = mRootComponent.getWMComponentBuilder().build();
if (mInitializeComponents) {
//然后初始化
mWMComponent.init();
}
//2. 再创建SysUIComponent
SysUIComponent.Builder builder = mRootComponent.getSysUIComponent();
if (mInitializeComponents) {
//将需要的各种食材,放入Builder,最后build()一下就是最终对象
//使用Builder,可以不用考虑这些函数的调用顺序,他们会在Builder类中被处理好
builder = prepareSysUIComponentBuilder(builder, mWMComponent)
.setPip(mWMComponent.getPip())
.setLegacySplitScreen(mWMComponent.getLegacySplitScreen())
.setSplitScreen(mWMComponent.getSplitScreen())
.setOneHanded(mWMComponent.getOneHanded())
.setBubbles(mWMComponent.getBubbles())
.setHideDisplayCutout(mWMComponent.getHideDisplayCutout())
.setShellCommandHandler(mWMComponent.getShellCommandHandler())
.setAppPairs(mWMComponent.getAppPairs())
.setTaskViewFactory(mWMComponent.getTaskViewFactory())
.setTransitions(mWMComponent.getTransitions())
.setStartingSurface(mWMComponent.getStartingSurface())
.setTaskSurfaceHelper(mWMComponent.getTaskSurfaceHelper());
} else {
builder = prepareSysUIComponentBuilder(builder, mWMComponent)
.setPip(Optional.ofNullable(null))
.setLegacySplitScreen(Optional.ofNullable(null))
.setSplitScreen(Optional.ofNullable(null))
.setOneHanded(Optional.ofNullable(null))
.setBubbles(Optional.ofNullable(null))
.setHideDisplayCutout(Optional.ofNullable(null))
.setShellCommandHandler(Optional.ofNullable(null))
.setAppPairs(Optional.ofNullable(null))
.setTaskViewFactory(Optional.ofNullable(null))
.setTransitions(Transitions.createEmptyForTesting())
.setStartingSurface(Optional.ofNullable(null))
.setTaskSurfaceHelper(Optional.ofNullable(null));
}
//创建,然后初始化
mSysUIComponent = builder.build();
if (mInitializeComponents) {
mSysUIComponent.init();
}
//3. 通过SysUIComponent获得Dependency对象,然后调用start()函数进行初始化,
// (似乎叫做init()函数更加合理一点)
Dependency dependency = mSysUIComponent.createDependency();
dependency.start();
}
在SystemUIFactory.init()函数中,主要做了四件事:
这4个对象,即为SystemUI整个应用需要用到的组件,通过这4个组件,就可以得到Dagger2中的各种各样的依赖。
在挨个介绍这4个对象之前。我们先处理一下前面的疑问,分别有:
回答问题1:因为SystemUIFactory不仅仅可以直接实例化SysetmUIFactory,有时还需要实例化SystemUIFactory的子类(比如TvSystemUIFactory),之所以需要有一个TvSystemUIFactory,是因为它需要一个不同版本的GlobalRootComponent叫做TvGloabRootComponent.而这个TvGlobalRootComponent继承于GlobalRootComponent
回答问题2:显然SystemUIFactory提供的实例创建更应该叫GloablRootComponentFactory。而不应该叫SystemUIFactory.我想这也是开发人员,不够严谨的地方。
当然,也可能还有我未理解到的意思
此时,SystemUIFactory其实已经没有什么内容可以介绍了,剩下的内容无外乎getter,内容简单,此处略过
接下来就是几个Component的创建过程了
GlobalRootComponent的创建,需要从它的图说起。在Android 12 源码分析 —— 应用层 二(SystemUI大体组织和启动过程):http://t.csdn.cn/AuzsL一文中,我们给GlobalRootComponent定义了一个Builder接口。
如下:
@Singleton
@Component(modules = {
GlobalModule.class,
SysUISubcomponentModule.class,
WMModule.class})
public interface GlobalRootComponent {
@Component.Builder
interface Builder {
@BindsInstance
Builder context(Context context);
GlobalRootComponent build();
}
//省略无关紧要部分
}
那么Dagger2对这个Builder是怎么生成的呢?
在编译的过程中,上面的Builder接口,将会被Dagger2实现,并生成一个名叫Builder的类。如下:
该类位于:
out/soong/.intermediates/frameworks/base/packages/SystemUI/SystemUI-core/android_common/kapt/gen/sources/com/android/systemui/dagger/DaggerGlobalRootComponent.java
private static final class Builder implements GlobalRootComponent.Builder {
private Context context;
@Override
public Builder context(Context context) {
//1. 先判断传入的参数是否为空
//2. 将传入的参数,赋值给内成员(这也是在上一篇文章中提及的BindsInstance的语义)
this.context = Preconditions.checkNotNull(context);
return this;
}
@Override
public GlobalRootComponent build() {
//1. 先判断context是否为空
//2. new一个DaggerGlobalRootComponennt对象,该对象就是Dagger2中实现
// GlobalRootComponent接口的对象
Preconditions.checkBuilderRequirement(context, Context.class);
return new DaggerGlobalRootComponent(new GlobalModule(), context);
}
}
接下来我们看看Dagger2对GlobalRootComponent的实现细节。
生成的文件位于:
out/soong/.intermediates/frameworks/base/packages/SystemUI/SystemUI-core/android_common/kapt/gen/sources/com/android/systemui/dagger/DaggerGlobalRootComponent.java
内容特别多,为了简化分析,我会缩进部分代码,并对其中的实现细节进行简化,因为他们的实现和前面介绍的模板几乎没有差别,现在只需对其结构进行了解。
public final class DaggerGlobalRootComponent implements GlobalRootComponent {
//定义一个成员变量,类型为Provider 它可以通过
//Provider.get() 得到对应的具体的对象
//正是这个get()函数,可以让成员真正被需要的时候才初始化
//这样可以减少内存的使用
//可将其理解为:Context的提供者(同前面的模板一起理解,几乎可以肯定,它的实现为
// DoubleCheck类)
private Provider<Context> contextProvider;
//省略余下的类似的成员定义
//构造器函数,Dagger2根据我们画的图,会正确的处理构造函数所需的依赖
private DaggerGlobalRootComponent(GlobalModule globalModuleParam, Context contextParam) {
this.context = contextParam;
initialize(globalModuleParam, contextParam);
}
//辅助构造函数的方法,用于初始化成员变量
@SuppressWarnings("unchecked")
private void initialize(final GlobalModule globalModuleParam, final Context contextParam) {
//在方法体中,Dagger2根据我们画的图,自动去找寻需要的对象,并初始化本对象成员
//这也正是Dagger2的最大作用,它可以简化我们的代码编写。自动帮我们完成各种各样的依赖
//方法体中的赋值相对简单。不做过多介绍
//这里面其实就是:使用DoubleCheck对成员进行初始化(结合前面的模板进行思考)
}
//同构造函数一样,mainResources你也不需要知道为什么会出现在这个地方(这属于Dagger2的内部
// 细节)。Dagger2会自动处理好对于这个函数的调用
private Resources mainResources() {
//AAA_BBBFactory通常表示,AAA类的BBB方法的工厂类,它实现了Factory接口
return FrameworkServicesModule_ProvideResourcesFactory.provideResources(context);
}
//同MainResources()函数一样,Dagger2自动处理好其调用
private Executor mainExecutor() {
return GlobalConcurrencyModule_ProvideMainExecutorFactory.provideMainExecutor(context);
}
//这个是实现的GlobalRootComponent的接口.在这个接口中,直接new了一个对象并返回
//倘若每次调用这个方法,则会创建不同的对象。这是因为他们的生命周期不一样
//GlobalRootComponent的生命周期为@SingleTton
//而WMComponent.Builder的生命周期为@WMSingleton
@Override
public WMComponent.Builder getWMComponentBuilder() {
return new WMComponentBuilder();
}
//同WMComponent.Builder一样,直接new了一个对象返回,因为其生命周期为
//@SysUISingleton
@Override
public SysUIComponent.Builder getSysUIComponent() {
return new SysUIComponentBuilder();
}
//对GlobalRootComponent的接口方法的实现。在实现中,使用了ThreadFactoryImpl_Factory类来
//实例化对象
//这里可能就会有以问题了,为何不是直接new一个对象,反而用了ThreadFactoryImpl_Factory来实例化
//因为在GlobalConcurrencyModule里面有如下的绑定关系
//@Binds
//public abstract ThreadFactory bindExecutorFactory(ThreadFactoryImpl impl)
//在需要ThreadFactory的时候,就会创建ThreadFactoryImpl实例。而ThreadFactoryImpl实例,
//则由
//其对应的工厂类(ThreadFactoryImpl_Factory)来创建
@Override
public ThreadFactory createThreadFactory() {
return ThreadFactoryImpl_Factory.newInstance();
}
//返回一个为空的Optional
private static <T> Provider<Optional<T>> absentJdkOptionalProvider() {
@SuppressWarnings("unchecked") // safe covariant cast
Provider<Optional<T>> provider = (Provider<Optional<T>>) ABSENT_JDK_OPTIONAL_PROVIDER;return provider;
}
//使用Provider包装一个非空的Optional,所有操作最后都会调用到其内部的delegate
private static final class PresentJdkOptionalInstanceProvider<T> implements Provider<Optional<T>> {}
//暂时未知
private static final class PresentJdkOptionalLazyProvider<T> implements Provider<Optional<Lazy<T>>> {}
//实现Builder接口
//各个接口,只是简单的setter
private static final class Builder implements GlobalRootComponent.Builder {}
//实现接口
private final class WMComponentBuilder implements WMComponent.Builder {}
//实现子组件,只要是其子组件,就在内部实现一个非静态的类,因为subcomponent含有
//component的所有依赖关系,因此需要实现为一个内部类,这样它就会持有一个对外部类的引用
//同理,WMComponentImpl的subcomponent也会在其内部出现
private final class WMComponentImpl implements WMComponent {}
//实现Builder
private final class SysUIComponentBuilder implements SysUIComponent.Builder {}
//实现子组件
private final class SysUIComponentImpl implements SysUIComponent {}
}
在对GlobalRootImpl接口的实现中,分别完成了如下的工作:
从上我们也可以看到,其和我们的Demo模板的生产,差异不大,只是体量变大了很多
接下来看看WMComponent的实现
WMComponent的定义如下
@WMSingleton
@Subcomponent(modules = {WMShellModule.class})
public interface WMComponent {
//@Subcomponent.Builder定义了Builder接口
//在上面,已经看到了WMComponent.Builder的接口实现了
@Subcomponent.Builder
interface Builder {
WMComponent build();
}
//默认方法,用来初始化整个Shell.此处可以暂时不用管Shell对应的逻辑语义
//实际上,你可以将其理解为对WindowManager的部分功能的封装并提供接口让用户与WM可以交互
//犹如Bash shell(Bourne-Again Shell)在OS中的作用
default void init() {
getShellInit().init();
}
//用来获取ShellInit的实现,它只会在上面的init函数中被调用
//ShellInit的抽象:表示对Shell进行初始化的一个入口点。
@WMSingleton
ShellInit getShellInit();
//返回一个Optional对象
@WMSingleton
Optional<ShellCommandHandler> getShellCommandHandler();
//省略类似部分
}
在上面的图中,我们“绘制”了WMComponent的Builder接口,同时还绘制了可以获取ShellInit的接口。
在查看Dagger2生成的代码之前,我们看看,我们是怎么绘制图,让Dagger2来生成ShellInit的。
再次注意:ShellInit的抽象表示的是WMShell的一个入口对象。
从上面的代码可以知道,WMComponent的模块有WMShellModule。直接搜寻其源码,查看是否有ShellInit的返回,发现并没有。但是WMShellModule的还包含一个WMShellBaseModule在其中可以搜寻到ShellInit的返回。如下
WMShellBaseModuel,告诉了Dagger2如何创建ShellInit对象,如下
@Module
public abstract class WMShellBaseModule{
//省略部分代码
//通过@Provides告诉Dagger2,当需要ShellInit的时候,将会调用本函数
//即返回ShellInitImpl的asShellInit()方法
//而ShellInitImpl的对象,则通过下一个方法进行提供
@WMSingleton
@Provides
static ShellInit provideShellInit(ShellInitImpl impl) {
return impl.asShellInit();
}
//告诉Dagger2如果需要ShellInitImpl对象的时候,则由本方法提供
//在本方法中,通过new一个ShellInitImpl对象来创建对应的ShellInitImpl
@WMSingleton
@Provides
static ShellInitImpl provideShellInitImpl(DisplayImeController displayImeController,
DragAndDropController dragAndDropController,
ShellTaskOrganizer shellTaskOrganizer,
Optional<BubbleController> bubblesOptional,
Optional<LegacySplitScreenController> legacySplitScreenOptional,
Optional<SplitScreenController> splitScreenOptional,
Optional<AppPairsController> appPairsOptional,
Optional<PipTouchHandler> pipTouchHandlerOptional,
FullscreenTaskListener fullscreenTaskListener,
Transitions transitions,
StartingWindowController startingWindow,
@ShellMainThread ShellExecutor mainExecutor) {
return new ShellInitImpl(displayImeController,
dragAndDropController,
shellTaskOrganizer,
bubblesOptional,
legacySplitScreenOptional,
splitScreenOptional,
appPairsOptional,
pipTouchHandlerOptional,
fullscreenTaskListener,
transitions,
startingWindow,
mainExecutor);
}
}
从上面的代码可以知道,WMShell的初始化入口点,是ShellInitImpl的asShellInit()方法返回的对象.至于该对象内部是如何进行初始化的,会在合适的时候介绍到,现在我们专注于WMComponent的各种初始化上
同理对WMComponent中的其他接口方法,实现细节类似。
接下来看看Dagger2对WMComponenet相关代码的实现。首先是其Builder的实现
在前文中的GlobalRootComponent的实现中,我们看到了WMComponent.Builder的实现,现将其内容展现如下:
public final class DaggerGlobalRootComponent implements GlobalRootComponent{
//省略部分代码
private final class WMComponentBuilder implements WMComponent.Builder{
@Override
public WMComponent build(){
//直接new一个WMComponentImpl,这个对象是对WMComponent接口的实现
return new WMComponentImpl();
}
}
//省略部分代码
}
接下来看看,Dagger2对WMComponent接口的实现。
WMComponent作为GlobalRootComponent的subcomponent,则WMComponent被放置在了DaggerGlobalRootComponent的内部,如下:
public final class DaggerGlobalRootComponent implements GlobalRootComponent{
//省略部分代码
private final class WMComponentImpl implements WMComponent {
//同component一样,将成员定义成Provider的封装
//只要在需要的时候才通过其Provider.get()方法获取其内部的实现
private Provider<Handler> provideShellMainHandlerProvider;
//省略相似代码
//生成的构造函数,通过调用initialize()方法进行初始化
private WMComponentImpl() {
initialize();
}
//对内部的成员进行初始化
@SuppressWarnings("unchecked")
private void initialize() {
//Dagger2自动找到需要的依赖,然后对本对象的成员,进行赋值初始化操作
}
//实现其对应的接口
@Override
public ShellInit getShellInit() {
return provideShellInitProvider.get();
}
//省略其他相似代码
}
//省略部分代码
}
从上面生成的代码中,我们看一看到WMComponent这个subcomponent 几乎和GlobalRootComponent的结构一致。
而这些生成内的东西,现在不需要关系,我们只需要知道其结构和大体抽象代码,在真正的业务实现细节中,会在有需要的地方进行提及。
再次提醒:WMComponent为Window Manager提供给SystemUI的交互接口。现在只需知道这一层抽象意义即可
接下来继续看看SysUIComponent.
先看看源码中,是如何定义SysUIComponent的,即我们如何绘制SysUIComponent的,如下:
@SysUISingleton
@Subcomponent(modules = {
DefaultComponentBinder.class,
DependencyProvider.class,
SystemUIBinder.class,
SystemUIModule.class,
SystemUIDefaultModule.class})
public interface SysUIComponent {
//又来Builder模式
//并传递WMComponent中相应的组件给SysUIComponent
//正是基于此,WMComponent组件的初始化必须在SysUIComponent组件之前完成
//且可以通过提供Optional>.empty()来替换其中的组件,这也是SystemUIFactory中的init()
//函数中的部分代码
@SysUISingleton
@Subcomponent.Builder
interface Builder {
//绑定实例,内容如前文,对应的语义见上一篇博文
@BindsInstance
Builder setPip(Optional<Pip> p);
//省略一些相似代码
//build函数,返回SysUIComponent接口的实现
//其实,仔细看过前面的WMComponent就会知道,返回的实例多半叫做SysUIComponentImpl
SysUIComponent build();
}
//默认的初始化操作,为了保持跟WMComponent一致的操作步调,这里依然有一个init()接口
//但是它的函数体为空
default void init() {
// Do nothing
}
//返回一个BootCompleteCacheImpl对象
//这个对象,我们在前一篇博文中介绍过,用于缓存是否所有的
//SystemUI服务都已经启动完成
//其实,这里读者可以思考一下,是否BootCompleteCacheImpl对象还会再需要?如果不需要了,
//它能被GC回收吗?
//如果不能回收,是不是代表BootCompleteCacheImpl的生命周期不应该这样设置?
@SysUISingleton
BootCompleteCacheImpl provideBootCacheImpl();
//返回一个Dependency对象
//Dependency对象,提供了SystemUI各个组件的快捷访问,后文我们将会其进行详细介绍
@SysUISingleton
Dependency createDependency();
//省略相同的代码
//inject接口,表示对PeopleProvider对象中,注入被@Inject标记的成员
void inject(PeopleProvider peopleProvider);
}
其实有了上面的注释,以及前面的模板,读者应该已经知道了Dagger2对上面的一些生成代码了。
接下来我们会先看对应的Builder接口的生成,然后再看SysUIComponent接口的生成
SysUIComponent.Builder接口依然在DaggerGlobalRootComponent类中,如下:
private final class SysUIComponentBuilder implements SysUIComponent.Builder {
//成员的定义,省略
//定义必要的成员,用于在build阶段生成最终的SysUIComponentImpl
//各种setter接口函数的实现,用于保存传入的参数,很简单,省略
//接口的build函数实现,先检查,然后new一个SysUIComponentImpl对象
@Override
public SysUIComponent build() {
Preconditions.checkBuilderRequirement(setPip, Optional.class);
Preconditions.checkBuilderRequirement(setLegacySplitScreen, Optional.class);
Preconditions.checkBuilderRequirement(setSplitScreen, Optional.class);
Preconditions.checkBuilderRequirement(setAppPairs, Optional.class);
Preconditions.checkBuilderRequirement(setOneHanded, Optional.class);
Preconditions.checkBuilderRequirement(setBubbles, Optional.class);
Preconditions.checkBuilderRequirement(setTaskViewFactory, Optional.class);
Preconditions.checkBuilderRequirement(setHideDisplayCutout, Optional.class);
Preconditions.checkBuilderRequirement(setShellCommandHandler, Optional.class);
Preconditions.checkBuilderRequirement(setTransitions, ShellTransitions.class);
Preconditions.checkBuilderRequirement(setStartingSurface, Optional.class);
Preconditions.checkBuilderRequirement(setTaskSurfaceHelper, Optional.class);
return new SysUIComponentImpl(new DependencyProvider(), new NightDisplayListenerModule(), new UserModule(), setPip, setLegacySplitScreen, setSplitScreen, setAppPairs, setOneHanded, setBubbles, setTaskViewFactory, setHideDisplayCutout, setShellCommandHandler, setTransitions, setStartingSurface, setTaskSurfaceHelper);
}
}
Builder函数的实现很是简单
接下来看看SysUIComponent的实现,其实到这里,大家已经非常熟悉了,它的结构等同于GlbalRootComponent,也等同于WMComponent
作为GlobalRootComponent的subcomponent,所以SysUIComponent的生成依然在DaggerGlobalRootComponent中,如下
public final class DaggerGlobalRootComponent implements GlobalRootComponent {
//省略不相干的部分
private final class SysUIComponentImpl implements SysUIComponent {
//省略成员定义,其结构和内容,相似于GlobalRootComponent和WMComponent,故不再啰嗦
//对应的构造函数
private SysUIComponentImpl(DependencyProvider dependencyProviderParam,
NightDisplayListenerModule nightDisplayListenerModuleParam, UserModule userModuleParam,
Optional<Pip> setPipParam, Optional<LegacySplitScreen> setLegacySplitScreenParam,
Optional<SplitScreen> setSplitScreenParam, Optional<AppPairs> setAppPairs,
Optional<OneHanded> setOneHandedParam, Optional<Bubbles> setBubblesParam,
Optional<TaskViewFactory> setTaskViewFactoryParam,
Optional<HideDisplayCutout> setHideDisplayCutoutParam,
Optional<ShellCommandHandler> setShellCommandHandlerParam,
ShellTransitions setTransitionsParam, Optional<StartingSurface> setStartingSurfaceParam,
Optional<TaskSurfaceHelper> setTaskSurfaceHelper) {
//因为成员函数过多,因此分成了7个初始化辅助函数进行初始化
}
//initialize,initialize1,initialize2,initialize3,initialize4,initialize5,
//initialize6
//这几个函数都是用于初始化成员的,其中初始化成员的方法和过程,跟GlobalRootComponent
//和WMComponent类似
@SuppressWarnings("unchecked")
private void initialize()
//实现的接口,省略,较简单
//对PeopleProvider中被@Inject标注的成员,进行赋值
@Override
public void inject(PeopleProvider peopleProvider) {
injectPeopleProvider(peopleProvider);
}
//使用辅助类 Type_MembersInjector。进行成员的赋值
//PeopleProvider_MembersInjector.injectMPeopleSpaceWidgetManager()的实现就为:
//instance.mPeopleSpaceWidgetManager = mPeopleSpaceWidget;
private PeopleProvider injectPeopleProvider(PeopleProvider instance) {
PeopleProvider_MembersInjector.injectMPeopleSpaceWidgetManager(instance, peopleSpaceWidgetManagerProvider.get());
return instance;
}
//SysUIComponent的subcomponent的builder的实现
private final class ExpandableNotificationRowComponentBuilder implements ExpandableNotificationRowComponent.Builder {}
//SysUIComponent的subcomponent的实现
private final class ExpandableNotificationRowComponentImpl implements ExpandableNotificationRowComponent {}
//SysUIComponent的subcomponent的Factory的实现
private final class KeyguardBouncerComponentFactory implements KeyguardBouncerComponent.Factory {}
//SysUIComponent的subcomponent的实现
private final class KeyguardBouncerComponentImpl implements KeyguardBouncerComponent {}
//省略相似部分
}
}
从上面的生成结果中,我们可以看到,SysUIComponent的生成,跟GlobalRootComponent很是类似。主要完成:
有了上面的介绍,现在基本上已经非常明确,各个组件的初始化过程和内部实现细节了。
接下来还剩下最后一个Dependency的实现细节
Dependency对应的抽象是什么?这里直接给出一个结论:为了方便在各个模块中能够直接引用Dagger2中的依赖。举个例子,如果我要通过SysUIComponent访问某个依赖,则可能出现如下的调用情况:
d=sysuicomponent.getxxx().getxxx().getxxx().getxxx();
d.xxx();
上面的代码中,出现了多层的getxxx()函数,因此,为了方便,将一些常见的依赖,通过Dependency来调用即可。现在提供的方法为:Dependency.get(依赖.class)从而获得对应的依赖
这也是这个类的名字的由来。
有了上面的观点就非常容易看懂Dependency.java文件了
如下:
@SysUISingleton
public class Dependency {
//一些简单的成员定义,省略
//由Dagger2进行创建
@Inject
public Dependency() {
}
//初始化各个依赖
protected void start() {
//mProviders是一个以Object为对象,以LazyDependencyCreator为值的Map
//LazyDependencyCreator封装创建依赖的方法,用于在需要的时候创建
mProviders.put(TIME_TICK_HANDLER, mTimeTickHandler::get);
//省略相似部分
//将Dependency对象保存在Static字段中,便于访问
Dependency.setInstance(this);
}
//省略一些简单的函数
//当访问某个具体的依赖时,最终的访问点
private synchronized <T> T getDependencyInner(Object key) {
@SuppressWarnings("unchecked")
//1. 首先检查依赖的缓存中,是否有对应的依赖,其中缓存使用了ArrayMap进行存储(注意其和
// HashMap之间的差别)
//2. 如果没有,调用createDependency创建
T obj = (T) mDependencies.get(key);
if (obj == null) {
obj = createDependency(key);
//3. 如果创建完成,就将其加入缓存中,方便未来调用。注意此处有同步控制,防止并发
// 带来的问题
mDependencies.put(key, obj);
//4. 如果某些依赖,需要使用dump功能,则将其注册到DumpManager。如同
// SystemUIService中的初始化最后部分一样
if (autoRegisterModulesForDump() && obj instanceof Dumpable) {
mDumpManager.registerDumpable(obj.getClass().getName(), (Dumpable) obj);
}
}
return obj;
}
//创建依赖的具体实现
@VisibleForTesting
public <T> T createDependency(Object cls) {
//1. 检查参数,必须是DependencyKey类型或者Class类型
Preconditions.checkArgument(cls instanceof DependencyKey<?> || cls instanceof Class<?>);
//2. 通过key,得到LazyDependencyCreator对象。这个对象通常封装着一个用于创建具
// 体对象的方法。如Lazy的get()方法
@SuppressWarnings("unchecked")
LazyDependencyCreator<T> provider = mProviders.get(cls);
if (provider == null) {
throw new IllegalArgumentException("Unsupported dependency " + cls
+ ". " + mProviders.size() + " providers known.");
}
//3. 调用封装的方法(如Lazy.get()),创建具体的对象
return provider.createDependency();
}
//定义延迟创建的一种封装形式
private interface LazyDependencyCreator<T> {
T createDependency();
}
//对依赖的key的封装
public static final class DependencyKey<V> {
private final String mDisplayName;
public DependencyKey(String displayName) {
mDisplayName = displayName;
}
@Override
public String toString() {
return mDisplayName;
}
}
//省略掉一些简单的代码
}
从上面可以知道,Dependency就做了两件事情:
至此,我们介绍了SystemUIFactory的init()方法中,重要组件的创建和初始化细节。也完成了整个SystemUI的启动
现在将整个启动过程,总结如下:
接下来,我们将进入SystemUI的UI部分。看看状态栏是如何被加入整个屏幕的。然后一步步拆分,查看下拉状态栏中的各个图标的实现
因为最近要上课,尽量保持一周一更