Dagger2在SystemUI中的应用

1,109 阅读4分钟

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清单文件里的组件的初始化

developer.android.com/reference/a…

在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关系图

share.mubu.com/doc/L_b7amv…

GlobalRootComponent.png