为了提升安卓项目的开发效率,开始学习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之间的区别
------------------------------------
注:大神路过,多多指点!