Dagger 2 在 Android 上的使用(六)
本文对系列的第一篇文章中的例子进行了分析总结。
本文首发:http://yuweiguocn.github.io/
《天净沙·秋思》
枯藤老树昏鸦,小桥流水人家,古道西风瘦马。
夕阳西下,断肠人在天涯。
-元代,马致远
Dagger 2 在 Android 上的使用(一)
Dagger 2 在 Android 上的使用(二)
Dagger 2 在 Android 上的使用(三)
Dagger 2 在 Android 上的使用(四)
Dagger 2 在 Android 上的使用(五)
前言
在前面的文章我们介绍了Dagger2 中的大部分注解的使用,接下来我们从源码角度分析下第一篇文章中例子的原理。
AppComponent
自定义组件AppComponent继承了AndroidInjector接口类,指定了Module类ActivityBindingModule和Dagger2中的AndroidSupportInjectionModule:
@Component(modules = {ActivityBindingModule.class,AndroidSupportInjectionModule.class})
public interface AppComponent extends AndroidInjector<App> {
}
AndroidInjector接口中包含一个inject用于注入的方法,和一个抽象Builder类,其中用到了我们在上文中介绍的@BindsInstance
注解,用于将注入的实例绑定到构建的依赖图中。
public interface AndroidInjector<T> {
void inject(T instance);
interface Factory<T> {
AndroidInjector<T> create(T instance);
}
abstract class Builder<T> implements AndroidInjector.Factory<T> {
@Override
public final AndroidInjector<T> create(T instance) {
seedInstance(instance);
return build();
}
@BindsInstance
public abstract void seedInstance(T instance);
public abstract AndroidInjector<T> build();
}
}
AndroidSupportInjectionModule中用@Multibinds
注解声明了Support中Fragment的多绑定,包括Fragment的Class的key和String的key两个集合,还用到了@Module
的includes
属性用于引入其它的Module进行组合:
@Beta
@Module(includes = AndroidInjectionModule.class)
public abstract class AndroidSupportInjectionModule {
@Multibinds
abstract Map<Class<? extends Fragment>, AndroidInjector.Factory<? extends Fragment>>
supportFragmentInjectorFactories();
@Multibinds
abstract Map<String, AndroidInjector.Factory<? extends Fragment>>
supportFragmentInjectorFactoriesWithStringKeys();
private AndroidSupportInjectionModule() {}
}
AndroidInjectionModule类中和AndroidSupportInjectionModule类似,声明了Android中四大组件Activity、Service、BroadcastReceiver、ContentProvider和Fragment的多绑定,只所以需要声明是由于这些Map集合有可能为空。
@Beta
@Module
public abstract class AndroidInjectionModule {
@Multibinds
abstract Map<Class<? extends Activity>, AndroidInjector.Factory<? extends Activity>>
activityInjectorFactories();
@Multibinds
abstract Map<String, AndroidInjector.Factory<? extends Activity>>
activityInjectorFactoriesWithStringKeys();
@Multibinds
abstract Map<Class<? extends Fragment>, AndroidInjector.Factory<? extends Fragment>>
fragmentInjectorFactories();
@Multibinds
abstract Map<String, AndroidInjector.Factory<? extends Fragment>>
fragmentInjectorFactoriesWithStringKeys();
@Multibinds
abstract Map<Class<? extends Service>, AndroidInjector.Factory<? extends Service>>
serviceInjectorFactories();
@Multibinds
abstract Map<String, AndroidInjector.Factory<? extends Service>>
serviceInjectorFactoriesWithStringKeys();
@Multibinds
abstract Map<
Class<? extends BroadcastReceiver>, AndroidInjector.Factory<? extends BroadcastReceiver>>
broadcastReceiverInjectorFactories();
@Multibinds
abstract Map<String, AndroidInjector.Factory<? extends BroadcastReceiver>>
broadcastReceiverInjectorFactoriesWithStringKeys();
@Multibinds
abstract Map<Class<? extends ContentProvider>, AndroidInjector.Factory<? extends ContentProvider>>
contentProviderInjectorFactories();
@Multibinds
abstract Map<String, AndroidInjector.Factory<? extends ContentProvider>>
contentProviderInjectorFactoriesWithStringKeys();
private AndroidInjectionModule() {}
}
ActivityBindingModule
下面是我们自定义的用于Activity绑定的Module类:
@Module
public abstract class ActivityBindingModule {
@ActivityScope
@ContributesAndroidInjector(modules = HomeModule.class)
abstract HomeActivity contributeHomeActivity();
}
注解@ContributesAndroidInjector
用于为该方法返回类型生成一个AndroidInjector。用在Module中的无参抽象方法上,返回参数为具体的Android框架类型(如:HomeActivity、MyFragment、MyService等),指定的Module将会被安装到生成的Subcomponent上。上面的代码将会生成下面的类:
@Module(subcomponents = ActivityBindingModule_ContributeHomeActivity.HomeActivitySubcomponent.class)
public abstract class ActivityBindingModule_ContributeHomeActivity {
private ActivityBindingModule_ContributeHomeActivity() {}
@Binds
@IntoMap
@ActivityKey(HomeActivity.class)
abstract AndroidInjector.Factory<? extends Activity> bindAndroidInjectorFactory(
HomeActivitySubcomponent.Builder builder);
@Subcomponent(modules = HomeModule.class)
@ActivityScope
public interface HomeActivitySubcomponent extends AndroidInjector<HomeActivity> {
@Subcomponent.Builder
abstract class Builder extends AndroidInjector.Builder<HomeActivity> {}
}
}
这里使用了多绑定以Activity的class为key和生成的子组件的Builder类为value绑定到了Map集合中。
DaggerAppComponent
上面类中的多绑定会在生成的Component类中生成提供该集合的方法,以及生成的子组件接口的实现类:
public final class DaggerAppComponent implements AppComponent {
private Provider<ActivityBindingModule_ContributeHomeActivity.HomeActivitySubcomponent.Builder>
homeActivitySubcomponentBuilderProvider;
private DaggerAppComponent(Builder builder) {
initialize(builder);
}
public static Builder builder() {
return new Builder();
}
public static AppComponent create() {
return new Builder().build();
}
private Map<Class<? extends Activity>, Provider<AndroidInjector.Factory<? extends Activity>>>
getMapOfClassOfAndProviderOfFactoryOf() {
return MapBuilder
.<Class<? extends Activity>, Provider<AndroidInjector.Factory<? extends Activity>>>
newMapBuilder(1)
.put(HomeActivity.class, (Provider) homeActivitySubcomponentBuilderProvider)
.build();
}
private DispatchingAndroidInjector<Activity> getDispatchingAndroidInjectorOfActivity() {
return DispatchingAndroidInjector_Factory.newDispatchingAndroidInjector(
getMapOfClassOfAndProviderOfFactoryOf(),
Collections.<String, Provider<AndroidInjector.Factory<? extends Activity>>>emptyMap());
}
@SuppressWarnings("unchecked")
private void initialize(final Builder builder) {
this.homeActivitySubcomponentBuilderProvider =
new Provider<
ActivityBindingModule_ContributeHomeActivity.HomeActivitySubcomponent.Builder>() {
@Override
public ActivityBindingModule_ContributeHomeActivity.HomeActivitySubcomponent.Builder
get() {
return new HomeActivitySubcomponentBuilder();
}
};
}
@Override
public void inject(App arg0) {
injectApp(arg0);
}
private App injectApp(App instance) {
DaggerApplication_MembersInjector.injectActivityInjector(
instance, getDispatchingAndroidInjectorOfActivity());
return instance;
}
public static final class Builder {
private Builder() {}
public AppComponent build() {
return new DaggerAppComponent(this);
}
}
private final class HomeActivitySubcomponentBuilder
extends ActivityBindingModule_ContributeHomeActivity.HomeActivitySubcomponent.Builder {
private HomeActivity seedInstance;
@Override
public ActivityBindingModule_ContributeHomeActivity.HomeActivitySubcomponent build() {
if (seedInstance == null) {
throw new IllegalStateException(HomeActivity.class.getCanonicalName() + " must be set");
}
return new HomeActivitySubcomponentImpl(this);
}
@Override
public void seedInstance(HomeActivity arg0) {
this.seedInstance = Preconditions.checkNotNull(arg0);
}
}
private final class HomeActivitySubcomponentImpl
implements ActivityBindingModule_ContributeHomeActivity.HomeActivitySubcomponent {
private Provider<HomeContract.Presenter> bindPresenterProvider;
private HomeActivitySubcomponentImpl(HomeActivitySubcomponentBuilder builder) {
initialize(builder);
}
@SuppressWarnings("unchecked")
private void initialize(final HomeActivitySubcomponentBuilder builder) {
this.bindPresenterProvider = DoubleCheck.provider((Provider) HomePresenter_Factory.create());
}
@Override
public void inject(HomeActivity arg0) {
injectHomeActivity(arg0);
}
private HomeActivity injectHomeActivity(HomeActivity instance) {
DaggerActivity_MembersInjector.injectFragmentInjector(
instance, DaggerAppComponent.this.getDispatchingAndroidInjectorOfFragment());
HomeActivity_MembersInjector.injectMPresenter(instance, bindPresenterProvider.get());
return instance;
}
}
}
DaggerApplication
我们在Application中继承了DaggerApplication类,并实现了applicationInjector方法返回了AppComponent类的实例:
public class App extends DaggerApplication {
@Override
protected AndroidInjector<? extends DaggerApplication> applicationInjector() {
return DaggerAppComponent.create();
}
}
DaggerApplication在onCreate方法中调用了我们实现的applicationInjector方法,然后调用inject方法完成了对成员变量的注入。
@Beta
public abstract class DaggerApplication extends Application
implements HasActivityInjector,
HasFragmentInjector,
HasServiceInjector,
HasBroadcastReceiverInjector,
HasContentProviderInjector {
@Inject DispatchingAndroidInjector<Activity> activityInjector;
@Inject DispatchingAndroidInjector<BroadcastReceiver> broadcastReceiverInjector;
@Inject DispatchingAndroidInjector<Fragment> fragmentInjector;
@Inject DispatchingAndroidInjector<Service> serviceInjector;
@Inject DispatchingAndroidInjector<ContentProvider> contentProviderInjector;
private volatile boolean needToInject = true;
@Override
public void onCreate() {
super.onCreate();
injectIfNecessary();
}
@ForOverride
protected abstract AndroidInjector<? extends DaggerApplication> applicationInjector();
private void injectIfNecessary() {
if (needToInject) {
synchronized (this) {
if (needToInject) {
@SuppressWarnings("unchecked")
AndroidInjector<DaggerApplication> applicationInjector =
(AndroidInjector<DaggerApplication>) applicationInjector();
applicationInjector.inject(this);
if (needToInject) {
throw new IllegalStateException(
"The AndroidInjector returned from applicationInjector() did not inject the "
+ "DaggerApplication");
}
}
}
}
}
@Inject
void setInjected() {
needToInject = false;
}
@Override
public DispatchingAndroidInjector<Activity> activityInjector() {
return activityInjector;
}
@Override
public DispatchingAndroidInjector<Fragment> fragmentInjector() {
return fragmentInjector;
}
@Override
public DispatchingAndroidInjector<BroadcastReceiver> broadcastReceiverInjector() {
return broadcastReceiverInjector;
}
@Override
public DispatchingAndroidInjector<Service> serviceInjector() {
return serviceInjector;
}
@Override
public AndroidInjector<ContentProvider> contentProviderInjector() {
injectIfNecessary();
return contentProviderInjector;
}
}
DaggerActivity
我们的Activity继承自了DaggerActivity,DaggerActivity类中实现HasFragmentInjector接口用于Fragment的注入,在onCreate方法中使用AndroidInjection类完成了Activity中所需的依赖注入。
@Beta
public abstract class DaggerActivity extends Activity implements HasFragmentInjector {
@Inject DispatchingAndroidInjector<Fragment> fragmentInjector;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
AndroidInjection.inject(this);
super.onCreate(savedInstanceState);
}
@Override
public AndroidInjector<Fragment> fragmentInjector() {
return fragmentInjector;
}
}
AndroidInjection
AndroidInjection是一个工具类,用于对Android框架中Activity、Fragment、Service、BroadcastReceiver、ContentProvider进行依赖注入。AndroidInjection会从Application中获取activityInjector方法的值进行依赖注入。
public final class AndroidInjection {
private static final String TAG = "dagger.android";
public static void inject(Activity activity) {
checkNotNull(activity, "activity");
Application application = activity.getApplication();
if (!(application instanceof HasActivityInjector)) {
throw new RuntimeException(
String.format(
"%s does not implement %s",
application.getClass().getCanonicalName(),
HasActivityInjector.class.getCanonicalName()));
}
AndroidInjector<Activity> activityInjector =
((HasActivityInjector) application).activityInjector();
checkNotNull(activityInjector, "%s.activityInjector() returned null", application.getClass());
activityInjector.inject(activity);
}
...
private AndroidInjection() {}
}
DispatchingAndroidInjector
DaggerApplication中activityInjector方法返回的是DispatchingAndroidInjector<Activity>类型,DispatchingAndroidInjector用于Android框架类型实例的成员变量的注入,首先对构造方法传入的两个集合进行了合并,然后在注入时根据类名从集合中获取对应实现类完成成员变量的注入。
public final class DispatchingAndroidInjector<T> implements AndroidInjector<T> {
private static final String NO_SUPERTYPES_BOUND_FORMAT =
"No injector factory bound for Class<%s>";
private static final String SUPERTYPES_BOUND_FORMAT =
"No injector factory bound for Class<%1$s>. Injector factories were bound for supertypes "
+ "of %1$s: %2$s. Did you mean to bind an injector factory for the subtype?";
private final Map<String, Provider<AndroidInjector.Factory<? extends T>>> injectorFactories;
@Inject
DispatchingAndroidInjector(
Map<Class<? extends T>, Provider<Factory<? extends T>>> injectorFactoriesWithClassKeys,
Map<String, Provider<Factory<? extends T>>> injectorFactoriesWithStringKeys) {
this.injectorFactories = merge(injectorFactoriesWithClassKeys, injectorFactoriesWithStringKeys);
}
private static <C, V> Map<String, V> merge(
Map<Class<? extends C>, V> classKeyedMap, Map<String, V> stringKeyedMap) {
if (classKeyedMap.isEmpty()) {
return stringKeyedMap;
}
Map<String, V> merged =
newLinkedHashMapWithExpectedSize(classKeyedMap.size() + stringKeyedMap.size());
merged.putAll(stringKeyedMap);
for (Entry<Class<? extends C>, V> entry : classKeyedMap.entrySet()) {
merged.put(entry.getKey().getName(), entry.getValue());
}
return Collections.unmodifiableMap(merged);
}
@CanIgnoreReturnValue
public boolean maybeInject(T instance) {
Provider<AndroidInjector.Factory<? extends T>> factoryProvider =
injectorFactories.get(instance.getClass().getName());
if (factoryProvider == null) {
return false;
}
@SuppressWarnings("unchecked")
AndroidInjector.Factory<T> factory = (AndroidInjector.Factory<T>) factoryProvider.get();
try {
AndroidInjector<T> injector =
checkNotNull(
factory.create(instance), "%s.create(I) should not return null.", factory.getClass());
injector.inject(instance);
return true;
} catch (ClassCastException e) {
throw new InvalidInjectorBindingException(
String.format(
"%s does not implement AndroidInjector.Factory<%s>",
factory.getClass().getCanonicalName(), instance.getClass().getCanonicalName()),
e);
}
}
@Override
public void inject(T instance) {
boolean wasInjected = maybeInject(instance);
if (!wasInjected) {
throw new IllegalArgumentException(errorMessageSuggestions(instance));
}
}
@Beta
public static final class InvalidInjectorBindingException extends RuntimeException {
InvalidInjectorBindingException(String message, ClassCastException cause) {
super(message, cause);
}
}
private String errorMessageSuggestions(T instance) {
List<String> suggestions = new ArrayList<>();
for (Class<?> clazz = instance.getClass(); clazz != null; clazz = clazz.getSuperclass()) {
if (injectorFactories.containsKey(clazz.getCanonicalName())) {
suggestions.add(clazz.getCanonicalName());
}
}
return suggestions.isEmpty()
? String.format(NO_SUPERTYPES_BOUND_FORMAT, instance.getClass().getCanonicalName())
: String.format(
SUPERTYPES_BOUND_FORMAT, instance.getClass().getCanonicalName(), suggestions);
}
}
总结
Dagger2使用多绑定和子组件功能将需要成员变量注入类的class和生成子组件实现类存入到Application的Map集合中,在Activity#onCreate方法中通过类名从Map集合中获取对应实现类完成了成员变量注入。