Dagger2注解基础
@Inject和@Component
- 用 @Inject 注解标注目标类中依赖类的实例对象
- 用 @Inject 注解标注依赖类的构造函数
- 若其他类还依赖于其他的类,则重复进行上面2个步骤
- 调用 Component(注入器)的 injectXXX(Object)方法开始注入
Component 就像 目标类 和自己的 依赖类 的媒介,把目标类依赖的实例注入到目标类中,来初始化目标类中的依赖实例变量。
@Module和@Provides
- 通过 @Module 注解类
- 通过 @Provides 注解方法
Component管理Module,而Module是一个简单工厂模式,Module 里面的方法都是创建相应类实例的方法。
@Provides 用以标注 Module 类中的方法,它的作用是 标注该 Module 可以向外界提供的类的实例对象的方法
@Qualifier和@Named
1.@Qualifier是限定符,是注解的注解
2.@Named则是基于String的限定符
当我有两个相同的依赖(都继承某一个父类或者都是先某一个接口)可以提供给高层时,那么程序就不知道我们到底要提供哪一个依赖,因为它找到了两个。这时候我们就可以通过限定符为两个依赖分别打上标记,指定提供某个依赖。
@Scope和@Singleton
- @Scope是注解的注解, Scope机制可以保证在 Scope 标记的 Component 作用域内 ,类会保持单例 。
- @Singleton是@Scope的一个默认实现
@Scope
@Documented
@Retention(RUNTIME)
public @interface Singleton {}
只要保证这个注解标记的 Component 在 App 进程中为单例的,并且得到正确的实现(被正确的标记到 类构造器 或 Module 中的 @Provides 标记的方法),那么它对应生成的类实例就是 单例的。
SystemUI中的dagger2使用
AppComponentFactory
SystemUI的application标签定义了一个appComponentFactory属性
AppComponentFactory用于控制manifest清单文件里的组件的初始化
https://developer.android.com/reference/android/app/AppComponentFactory
在manifest清单文件里的组件构建对象时会调用这些方法
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
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 resolve(String className, Map, Provider> creators) {
try {
Class clazz = Class.forName(className);
Provider 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, Provider> mActivityCreators;
private final Map, Provider> mServiceCreContextComponentHelper声明在dagger组件中获取,实现类是ContextComponentResolverators;
private final Map, Provider> mSystemUICreators;
private final Map, Provider> mRecentsCreators;
private final Map, Provider> mBroadcastReceiverCreators;
@Inject
ContextComponentResolver(Map, Provider> activityCreators,
Map, Provider> serviceCreators,
Map, Provider> systemUICreators,
Map, Provider> recentsCreators,
Map, Provider> 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