Dagger 2 在 Android 上的使用(六)
本文對系列的第一篇文章中的例子進行了分析總結。
本文首發:http://yuweiguocn.github.io/
《天淨沙·秋思》
枯藤老樹昏鴉,小橋流水人家,古道西風瘦馬。
夕陽西下,斷腸人在天涯。
-元代,馬致遠
前言
在前面的文章我們介紹了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集合中獲取對應實現類完成了成員變數注入。