爲了提升安卓項目的開發效率,開始學習Kotlin,在Kotlin官方文檔看到Dagger這個東東,因而開始學習Dagger(學海無涯苦做舟),看了Dagger官方文檔,看不懂(詞彙量,心裏一萬頭草泥馬奔騰),因而去看了一位前輩的入門教程,這篇教程講解@Inject、@Provides、@Module、@Component之間是聯繫,看了以後受益不淺,可是還有一些疑問沒有解決,如@BindsInstance、@Scope、Lazy<T>等,html
注:本篇沒有講解@Inject、@Provides、@Module、@Component相關的知識。java
因而基於項目android-architecture分支(todo-mvp-dagger)開始學習Dagger.android
縮寫:git
從應用入口TodoApplication開始分析,TodoApplication繼承DaggerApplicationgithub
public abstract class DaggerApplication extends Application ... { @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"); } } } } } }
DaggerApplication是dagger-android提供的,從上面的代碼片斷能夠看出,當應用啓動的時候,會調用applicationInjector(),AI.inject(DaggerApplication),applicationInjector()無非就是返回一個AI的實現類,咱們直接看實現類DaggerAppComponet在inject方法中作了什麼app
public final class DaggerAppComponent implements AppComponent { private MembersInjector<DaggerApplication> daggerApplicationMembersInjector; private void initialize(final Builder builder) { this.daggerApplicationMembersInjector = DaggerApplication_MembersInjector.create( dispatchingAndroidInjectorProvider, dispatchingAndroidInjectorProvider2, dispatchingAndroidInjectorProvider3, dispatchingAndroidInjectorProvider4, dispatchingAndroidInjectorProvider5); } @Override public void inject(DaggerApplication instance) { daggerApplicationMembersInjector.injectMembers(instance); } }
此時又出現一個新類,不着急,咱們再來看,DaggerApplication_MembersINjector.inject()方法作了什麼dom
public final class DaggerApplication_MembersInjector implements MembersInjector<DaggerApplication> { @Override public void injectMembers(DaggerApplication instance) { if (instance == null) { throw new NullPointerException("Cannot inject members into a null reference"); } instance.activityInjector = activityInjectorProvider.get(); instance.broadcastReceiverInjector = broadcastReceiverInjectorProvider.get(); instance.fragmentInjector = fragmentInjectorProvider.get(); instance.serviceInjector = serviceInjectorProvider.get(); instance.contentProviderInjector = contentProviderInjectorProvider.get(); instance.setInjected(); } }
看到這裏是否是恍然大悟,inject()就是給DagerApplication中@Inject註釋的屬性賦值,調用DagerApplication中@Inject註釋的方法。後面的AppComponent.inject(TodoApplication)同樣。ide
課外知識:volatile詳解。函數
接下來咱們分析dispatchingAndroidInjectorProvider等Provider是怎麼來的呢學習
public final class DaggerAppComponent implements AppComponent { private Provider<DispatchingAndroidInjector<Activity>> dispatchingAndroidInjectorProvider; private void initialize(final Builder builder) { this.dispatchingAndroidInjectorProvider = DispatchingAndroidInjector_Factory.create(mapOfClassOfAndProviderOfFactoryOfProvider); } }
DispatchAndroidInjector_Factory怎麼來的,有待學習,本人分析是基於AndroidInjectionModule生成。AndroidInjectionModule有一個關鍵詞是@Multibinds,有待學習。
課外知識:multibindings
從上面@Inject到@Module暫時沒法看出Dagger規則。
--------------------------------------------
接下來咱們從TodoApplication的屬性tasksRepository進行逆向追蹤分析,先上兩個代碼片斷
public final class DaggerAppComponent implements AppComponent { private MembersInjector<ToDoApplication> toDoApplicationMembersInjector; private void initialize(final Builder builder) { this.toDoApplicationMembersInjector = ToDoApplication_MembersInjector.create( dispatchingAndroidInjectorProvider, dispatchingAndroidInjectorProvider2, dispatchingAndroidInjectorProvider3, dispatchingAndroidInjectorProvider4, dispatchingAndroidInjectorProvider5, tasksRepositoryProvider); } @Override public void inject(ToDoApplication application) { toDoApplicationMembersInjector.injectMembers(application); }
public final class ToDoApplication_MembersInjector implements MembersInjector<ToDoApplication> { @Override public void injectMembers(ToDoApplication instance) { if (instance == null) { throw new NullPointerException("Cannot inject members into a null reference"); } dagger.android.DaggerApplication_MembersInjector.injectActivityInjector( instance, activityInjectorProvider); dagger.android.DaggerApplication_MembersInjector.injectBroadcastReceiverInjector( instance, broadcastReceiverInjectorProvider); dagger.android.DaggerApplication_MembersInjector.injectFragmentInjector( instance, fragmentInjectorProvider); dagger.android.DaggerApplication_MembersInjector.injectServiceInjector( instance, serviceInjectorProvider); dagger.android.DaggerApplication_MembersInjector.injectContentProviderInjector( instance, contentProviderInjectorProvider); dagger.android.DaggerApplication_MembersInjector.injectSetInjected(instance); instance.tasksRepository = tasksRepositoryProvider.get();//在這裏,在這裏,在這裏 } }
問題:DaggerApplication的activityInjector等被賦值了兩次。
此時咱們看到TodoApplication的屬性tasksRepository賦值的地方,咱們再來逆向追蹤Provider
public final class DaggerAppComponent implements AppComponent { private Provider<TasksRepository> tasksRepositoryProvider; private void initialize(final Builder builder) { this.tasksRepositoryProvider = DoubleCheck.provider( TasksRepository_Factory.create( provideTasksRemoteDataSourceProvider, provideTasksLocalDataSourceProvider)); } }
TasksRepository_Factory是怎麼來的,是由於TasksRepository的構造函數有@Inject註釋
@Singleton public class TasksRepository implements TasksDataSource { @Inject TasksRepository(@Remote TasksDataSource tasksRemoteDataSource, @Local TasksDataSource tasksLocalDataSource) { mTasksRemoteDataSource = tasksRemoteDataSource; mTasksLocalDataSource = tasksLocalDataSource; } }
逆向追蹤一下provideTasksLocalDataSourceProvider
public final class DaggerAppComponent implements AppComponent { private Provider<Application> applicationProvider; private Provider<TasksDataSource> provideTasksLocalDataSourceProvider; private void initialize(final Builder builder) { this.applicationProvider = InstanceFactory.create(builder.application); this.provideTasksLocalDataSourceProvider = DoubleCheck.provider( TasksRepositoryModule_ProvideTasksLocalDataSourceFactory.create( builder.tasksRepositoryModule, applicationProvider)); } }
又發現一個生成類:TasksRepositoryModule_ProvideTasksLocalDataSourceFactory
public final class TasksRepositoryModule_ProvideTasksLocalDataSourceFactory implements Factory<TasksDataSource> { private final TasksRepositoryModule module; private final Provider<Application> contextProvider; public TasksRepositoryModule_ProvideTasksLocalDataSourceFactory( TasksRepositoryModule module, Provider<Application> contextProvider) { assert module != null; this.module = module; assert contextProvider != null; this.contextProvider = contextProvider; } @Override public TasksDataSource get() { return Preconditions.checkNotNull( module.provideTasksLocalDataSource(contextProvider.get()), "Cannot return null from a non-@Nullable @Provides method"); } public static Factory<TasksDataSource> create( TasksRepositoryModule module, Provider<Application> contextProvider) { return new TasksRepositoryModule_ProvideTasksLocalDataSourceFactory(module, contextProvider); } }
@Module public class TasksRepositoryModule { @Singleton @Provides @Local TasksDataSource provideTasksLocalDataSource(Application context) { return new TasksLocalDataSource(context); } @Singleton @Provides @Remote TasksDataSource provideTasksRemoteDataSource() { return new TasksRemoteDataSource(); } }
結合從上面幾個代碼片斷,得出以下幾個結論:
--------------------------------------------
接下來,咱們再作一個正向分析,
----------------------------------------------
緊接着從應用入口TasksActivity開始分析,TasksActivity繼承了DaggerAppComatActivity
public abstract class DaggerAppCompatActivity extends AppCompatActivity implements HasFragmentInjector, HasSupportFragmentInjector { @Inject DispatchingAndroidInjector<Fragment> supportFragmentInjector; @Inject DispatchingAndroidInjector<android.app.Fragment> frameworkFragmentInjector; @Override protected void onCreate(Bundle savedInstanceState) { AndroidInjection.inject(this);//看這裏,看這裏,看這裏 super.onCreate(savedInstanceState); } @Override public AndroidInjector<Fragment> supportFragmentInjector() { return supportFragmentInjector; } @Override public AndroidInjector<android.app.Fragment> fragmentInjector() { return frameworkFragmentInjector; } }
AndroidInjection.inject(this)應該爲@Inject註釋的屬性賦值,爲了驗證這個想法,進去看一下
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().getCanonicalName()); activityInjector.inject(activity); } }
直接用DaggerApplication中已經注入的對象(DAI<Activity>)進行賦值,DAI.inject()會從其injectorFactories中尋找Activity對應的AI.Factory,使用這個Factory建立一個AI的實現類。因爲涉及代碼比較多,此處只列出調用棧是:
DAI.inject()
DaggerAppComponent.bindAndroidInjectorFactoryProvider.get()
TasksActivitySubcomponentBuilder.setInstance
TasksActivitySubcomponentBuilder.build
TasksActivitySubcomponentImpl.inject
public final class DaggerAppComponent implements AppComponent { private final class TasksActivitySubcomponentImpl implements ActivityBindingModule_TasksActivity.TasksActivitySubcomponent { private MembersInjector<TasksActivity> tasksActivityMembersInjector; private void initialize(final TasksActivitySubcomponentBuilder builder) { this.tasksActivityMembersInjector = TasksActivity_MembersInjector.create( dispatchingAndroidInjectorProvider, DaggerAppComponent.this.dispatchingAndroidInjectorProvider3, tasksPresenterProvider, tasksFragmentProvider); } @Override public void inject(TasksActivity arg0) { tasksActivityMembersInjector.injectMembers(arg0); } } }
第一個參數:dispatchingAndroidInjectorProvider是android.support.v4.app.Fragment的Provider,最終會賦值給DaggerFragment.childFragmentInjector
第二個參數:使用DaggerAppComponent的dispatchingAndroidInjectorProvider3,是android.app.Fragment的Provider,
第三個參數:是TasksActivity中@Inject註釋的mTaskPresenter的Provider
第四個參數:是TasksActivity中@Inject註釋的taskFragmentProvider的Provider
---------------------------------------
TasksActivitySubcomponentImpl怎麼來的,@ContributesAndroidInjector標註的方法
@Module public abstract class ActivityBindingModule { @ActivityScoped @ContributesAndroidInjector(modules = TasksModule.class) abstract TasksActivity tasksActivity(); @ActivityScoped @ContributesAndroidInjector(modules = AddEditTaskModule.class) abstract AddEditTaskActivity addEditTaskActivity(); @ActivityScoped @ContributesAndroidInjector(modules = StatisticsModule.class) abstract StatisticsActivity statisticsActivity(); @ActivityScoped @ContributesAndroidInjector(modules = TaskDetailPresenterModule.class) abstract TaskDetailActivity taskDetailActivity(); }
ContributesAndroidInjector的描述:
Generates an AndroidInjector for the return type of this method. The injector is implemented with a dagger.Subcomponent and will be a child of the dagger.Module's component.
This annotation must be applied to an abstract method in a dagger.Module that returns a concrete Android framework type (e.g. FooActivity, BarFragment, MyService, etc). The method should have no parameters.
詞彙量有限,參照代碼差很少理解了,@ContributesAndroidInjector註釋的方法必須抽象方法而且在一個Module,返回值必須Android中Activity,Fragment,Service等組件,最終會生成一個Subcomponent,歸屬於一個Component
----------------------------------------
緊接着看TasksFragment
@ActivityScoped public class TasksFragment extends DaggerFragment implements TasksContract.View { @Inject TasksContract.Presenter mPresenter; @Inject public TasksFragment() { // Requires empty public constructor } }
看到Inject,再來尋找Module和Provider
@Module public abstract class TasksModule { @FragmentScoped @ContributesAndroidInjector abstract TasksFragment tasksFragment(); @ActivityScoped @Binds abstract TasksContract.Presenter taskPresenter(TasksPresenter presenter); }
基於前面的結論,TasksModule.tasksFragment()做用是在DaggerAppComponent中必然有一個類TasksFragmentSubcomponentImpl
public final class DaggerAppComponent implements AppComponent { private final class TasksFragmentSubcomponentBuilder extends TasksModule_TasksFragment.TasksFragmentSubcomponent.Builder { } private final class TasksFragmentSubcomponentImpl implements TasksModule_TasksFragment.TasksFragmentSubcomponent { private MembersInjector<TasksFragment> tasksFragmentMembersInjector; private TasksFragmentSubcomponentImpl(TasksFragmentSubcomponentBuilder builder) { assert builder != null; initialize(builder); } @SuppressWarnings("unchecked") private void initialize(final TasksFragmentSubcomponentBuilder builder) { this.tasksFragmentMembersInjector = TasksFragment_MembersInjector.create( TasksActivitySubcomponentImpl.this.dispatchingAndroidInjectorProvider, TasksActivitySubcomponentImpl.this.taskPresenterProvider); } @Override public void inject(TasksFragment arg0) { tasksFragmentMembersInjector.injectMembers(arg0); } } } }
@Binds的做用
Annotates abstract methods of a Module that delegate bindings. For example, to bind java.util.Random to java.security.SecureRandom a module could declare the following: @Binds abstract Random bindRandom(SecureRandom secureRandom);
@Binds methods are a drop-in replacement for Provides methods that simply return an injected parameter. Prefer @Binds because the generated implementation is likely to be more efficient.
A @Binds method:
- Must be abstract.
- May be scoped.
- May be qualified.
- Must have a single parameter whose type is assignable to the return type. The return type declares the bound type (just as it would for a @Provides method) and the parameter is the type to which it is bound.
基於上面的描述以及代碼,@Bind註釋的TasksModule.taskPresenter()做用是生成尋找TasksPresenter的Provider最終賦值給Presenter的Providers
----------------------------------------
@Singleton的做用:標註的類,只會建立一個對象,如始終用的tasksRepositoryProvider
----------------------------------------
@Scope的做用:
A scope annotation applies to a class containing an injectable constructor and governs how the injector reuses instances of the type.
A scope annotation:
- is annotated with @Scope, @Retention(RUNTIME), and typically @Documented.
- should not have attributes.
- is typically not @Inherited, so scoping is orthogonal to implementation inheritance.
- may have restricted usage if annotated with @Target. While this specification covers applying scopes to classes only, some injector configurations might use scope annotations in other places (on factory method results for example).
以@ActivityScoped爲例
public class TasksActivity extends DaggerAppCompatActivity { @Inject TasksPresenter mTasksPresenter; @Inject Lazy<TasksFragment> taskFragmentProvider; } @Module public abstract class ActivityBindingModule { @ActivityScoped @ContributesAndroidInjector(modules = TasksModule.class) abstract TasksActivity tasksActivity(); } @ActivityScoped public class TasksFragment extends DaggerFragment implements TasksContract.View { } @ActivityScoped final class TasksPresenter implements TasksContract.Presenter { }
上面的代碼是爲了保證,TasksPresenter和taskFragmentProvider的生命週期只在TasksActivity內
------------------------------------
Lazy<T>的API文檔很清楚的描述direct injection、provider injection、lazy injection之間的區別
------------------------------------
注:大神路過,多多指點!