Dagger2在SystemUI中的应用

Dagger2注解基础

@Inject和@Component

  1. 用 @Inject 注解标注目标类中依赖类的实例对象
  2. 用 @Inject 注解标注依赖类的构造函数
  3. 若其他类还依赖于其他的类,则重复进行上面2个步骤
  4. 调用 Component(注入器)的 injectXXX(Object)方法开始注入

Component 就像 目标类 和自己的 依赖类 的媒介,把目标类依赖的实例注入到目标类中,来初始化目标类中的依赖实例变量。

@Module和@Provides

  1. 通过 @Module 注解类
  2. 通过 @Provides 注解方法

Component管理Module,而Module是一个简单工厂模式,Module 里面的方法都是创建相应类实例的方法。
@Provides 用以标注 Module 类中的方法,它的作用是 标注该 Module 可以向外界提供的类的实例对象的方法

@Qualifier和@Named

1.@Qualifier是限定符,是注解的注解
2.@Named则是基于String的限定符

当我有两个相同的依赖(都继承某一个父类或者都是先某一个接口)可以提供给高层时,那么程序就不知道我们到底要提供哪一个依赖,因为它找到了两个。这时候我们就可以通过限定符为两个依赖分别打上标记,指定提供某个依赖。

@Scope和@Singleton

  1. @Scope是注解的注解, Scope机制可以保证在 Scope 标记的 Component 作用域内 ,类会保持单例 。
  2. @Singleton是@Scope的一个默认实现
@Scope
@Documented
@Retention(RUNTIME)
public @interface Singleton {}

只要保证这个注解标记的 Component 在 App 进程中为单例的,并且得到正确的实现(被正确的标记到 类构造器 或 Module 中的 @Provides 标记的方法),那么它对应生成的类实例就是 单例的。

SystemUI中的dagger2使用

AppComponentFactory

SystemUI的application标签定义了一个appComponentFactory属性

<application
    ...
    android:appComponentFactory=".SystemUIAppComponentFactory">

AppComponentFactory用于控制manifest清单文件里的组件的初始化

https://developer.android.com/reference/android/app/AppComponentFactory

在manifest清单文件里的组件构建对象时会调用这些方法

47cebae4-ee7e-4966-9c64-52b4eccb02a5.png

SystemUIFactory

src/com/android/systemui/SystemUIAppComponentFactory.java

public Application instantiateApplicationCompat(
        @NonNull ClassLoader cl, @NonNull String className)
        throws InstantiationException, IllegalAccessException, ClassNotFoundException {
    Application app = super.instantiateApplicationCompat(cl, className);
    if (app instanceof ContextInitializer) {
        ((ContextInitializer) app).setContextAvailableCallback(
                context -> {
                    SystemUIFactory.createFromConfig(context);
                    SystemUIFactory.getInstance().getSysUIComponent().inject(
                            SystemUIAppComponentFactory.this);
                }
        );
    }

    return app;
}

在SystemUIApplication onCreate时回调 ContextAvailableCallback, 构建SystemUIFactory,并对它进行初始化

src/com/android/systemui/SystemUIFactory.java

public static void createFromConfig(Context context, boolean fromTest) {
    if (mFactory != null) {
        return;
    }

    final String clsName = context.getString(R.string.config_systemUIFactoryComponent);
    if (clsName == null || clsName.length() == 0) {
        throw new RuntimeException("No SystemUIFactory component configured");
    }

    try {
        Class<?> cls = null;
        cls = context.getClassLoader().loadClass(clsName);
        // 创建SystemUIFactory实例
        mFactory = (SystemUIFactory) cls.newInstance();
        // 初始化SystemUIFactory
        mFactory.init(context, fromTest);
    } catch (Throwable t) {
        Log.w(TAG, "Error creating SystemUIFactory component: " + clsName, t);
        throw new RuntimeException(t);
    }
}

public void init(Context context, boolean fromTest)
        throws ExecutionException, InterruptedException {
    ...
    // 获取dagger组件
    mRootComponent = buildGlobalRootComponent(context);
    ...

    // 获取systemui的dagger组件
    // And finally, retrieve whatever SysUI needs from WMShell and build SysUI.
    SysUIComponent.Builder builder = mRootComponent.getSysUIComponent();
    mSysUIComponent = builder.build();
    ...

    // 构建Dependency实例并初始化
    // 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();
}

protected GlobalRootComponent buildGlobalRootComponent(Context context) {
    return DaggerGlobalRootComponent.builder()
            .context(context)
            .build();
}

Dependency组件使用@Lazy标签懒加载:
首先构建LazyDependencyCreator放入mProviders,然后在真正使用dependency时调用createDependency进行创建

src/com/android/systemui/Dependency.java

private final ArrayMap<Object, Object> mDependencies = new ArrayMap<>();
private final ArrayMap<Object, LazyDependencyCreator> mProviders = new ArrayMap<>();

@Inject Lazy<ActivityStarter> mActivityStarter;
@Inject Lazy<BroadcastDispatcher> mBroadcastDispatcher;
@Inject Lazy<AsyncSensorManager> mAsyncSensorManager;
@Inject Lazy<BluetoothController> mBluetoothController;

protected void start() {
    // 构建LazyDependencyCreator放入mProviders
    mProviders.put(TIME_TICK_HANDLER, mTimeTickHandler::get);
    mProviders.put(BG_LOOPER, mBgLooper::get);
    mProviders.put(MAIN_LOOPER, mMainLooper::get);
    mProviders.put(MAIN_HANDLER, mMainHandler::get);
    mProviders.put(MAIN_EXECUTOR, mMainExecutor::get);
    mProviders.put(BACKGROUND_EXECUTOR, mBackgroundExecutor::get);
    mProviders.put(ActivityStarter.class, mActivityStarter::get);
    mProviders.put(BroadcastDispatcher.class, mBroadcastDispatcher::get);
...

// 获取dependency
private synchronized <T> T getDependencyInner(Object key) {
    @SuppressWarnings("unchecked")
    T obj = (T) mDependencies.get(key);
    if (obj == null) {
        // 若未创建则创建
        obj = createDependency(key);
        mDependencies.put(key, obj);
        ...
    }
    return obj;
}

public <T> T createDependency(Object cls) {
    Preconditions.checkArgument(cls instanceof DependencyKey<?> || cls instanceof Class<?>);

    @SuppressWarnings("unchecked")
    LazyDependencyCreator<T> provider = mProviders.get(cls);
    if (provider == null) {
        throw new IllegalArgumentException("Unsupported dependency " + cls
                + ". " + mProviders.size() + " providers known.");
    }

    // 这里调用的就是lazy.get()
    return provider.createDependency();
}

private interface LazyDependencyCreator<T> {
    T createDependency();
}

ContextComponentResolver

Application创建好之后SystemUI的主Service将启动起来,并逐个启动其他Service。

src/com/android/systemui/SystemUIService.java

public void onCreate() {
    super.onCreate();
    // Start all of SystemUI
    ((SystemUIApplication) getApplication()).startServicesIfNeeded();
    ...
}

ContextComponentHelper声明在dagger组件中获取,实现类是ContextComponentResolver

src/com/android/systemui/SystemUIApplication.java

private void startServicesIfNeeded(String metricsPrefix, String[] services) {
    ...
    final int N = services.length;
    for (int i = 0; i < N; i++) {
        String clsName = services[i];
        if (DEBUG) Log.d(TAG, "loading: " + clsName);
        log.traceBegin(metricsPrefix + clsName);
        long ti = System.currentTimeMillis();
        try {
            // 从ContextComponentHelper中获取对应组件的实例
            SystemUI obj = mComponentHelper.resolveSystemUI(clsName);
            if (obj == null) {
                Constructor constructor = Class.forName(clsName).getConstructor(Context.class);
                obj = (SystemUI) constructor.newInstance(this);
            }
            mServices[i] = obj;
        } catch (ClassNotFoundException
                | NoSuchMethodException
                | IllegalAccessException
                | InstantiationException
                | InvocationTargetException ex) {
            throw new RuntimeException(ex);
        }

        if (DEBUG) Log.d(TAG, "running: " + mServices[i]);
        // 调用SystemUI组件的start()方法
        mServices[i].start();

ContextComponentHelper声明在dagger组件中获取,实现类是ContextComponentResolver

src/com/android/systemui/dagger/SysUIComponent.java

@SysUISingleton
ContextComponentHelper getContextComponentHelper();

@Override
public SystemUI resolveSystemUI(String className) {
    return resolve(className, mSystemUICreators);
}

private <T> T resolve(String className, Map<Class<?>, Provider<T>> creators) {
    try {
        Class<?> clazz = Class.forName(className);
        Provider<T> provider = creators.get(clazz);
        return provider == null ? null : provider.get();
    } catch (ClassNotFoundException e) {
        return null;
    }
}

MultiBinding

ContextComponentResolver的构建方法里,activity、service、systemui组件、recents组件、broadcastreceiver作为参数放到Map里储存。

src/com/android/systemui/dagger/ContextComponentResolver.java

@SysUISingleton
public class ContextComponentResolver implements ContextComponentHelper {
    private final Map<Class<?>, Provider<Activity>> mActivityCreators;
    private final Map<Class<?>, Provider<Service>> mServiceCreContextComponentHelper声明在dagger组件中获取,实现类是ContextComponentResolverators;
    private final Map<Class<?>, Provider<SystemUI>> mSystemUICreators;
    private final Map<Class<?>, Provider<RecentsImplementation>> mRecentsCreators;
    private final Map<Class<?>, Provider<BroadcastReceiver>> mBroadcastReceiverCreators;

    @Inject
    ContextComponentResolver(Map<Class<?>, Provider<Activity>> activityCreators,
            Map<Class<?>, Provider<Service>> serviceCreators,
            Map<Class<?>, Provider<SystemUI>> systemUICreators,
            Map<Class<?>, Provider<RecentsImplementation>> recentsCreators,
            Map<Class<?>, Provider<BroadcastReceiver>> broadcastReceiverCreators) {
        mActivityCreators = activityCreators;
        mServiceCreators = serviceCreators;
        mSystemUICreators = systemUICreators;
        mRecentsCreators = recentsCreators;
        mBroadcastReceiverCreators = broadcastReceiverCreators;
    }

构建的来源是systemuicomponent的各个module,使用@IntoMap和@ClassKey进行MultiBinding

以SystemUI组件为例

src/com/android/systemui/dagger/SystemUIBinder.java

@Module(includes = {RecentsModule.class, StatusBarModule.class, KeyguardModule.class})
public abstract class SystemUIBinder {
    /** Inject into AuthController. */
    @Binds
    @IntoMap
    @ClassKey(AuthController.class)
    public abstract SystemUI bindAuthController(AuthController service);

    /** Inject into GarbageMonitor.Service. */
    @Binds
    @IntoMap
    @ClassKey(GarbageMonitor.Service.class)
    public abstract SystemUI bindGarbageMonitorService(GarbageMonitor.Service sysui);

    /** Inject into GlobalActionsComponent. */
    @Binds
    @IntoMap
    @ClassKey(GlobalActionsComponent.class)
    public abstract SystemUI bindGlobalActionsComponent(GlobalActionsComponent sysui);

    /** Inject into InstantAppNotifier. */
    @Binds
    @IntoMap
    @ClassKey(InstantAppNotifier.class)
    public abstract SystemUI bindInstantAppNotifier(InstantAppNotifier sysui);

    /** Inject into KeyguardViewMediator. */
    @Binds
    @IntoMap
    @ClassKey(KeyguardViewMediator.class)
    public abstract SystemUI bindKeyguardViewMediator(KeyguardViewMediator sysui);
    
}  

SystemUI的Component关系图

https://share.mubu.com/doc/L_b7amvpKP

GlobalRootComponent.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容