Dagger学习之阅读篇

为了提升安卓项目的开发效率,开始学习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

  • AndroidInjector -> AI
  • DispatchingAndroidInjector -> DAI
  • MembersInjectors -> MI

从应用入口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();
    }

}

结合从上面几个代码片断,得出以下几个结论:

  1. @Inject注释的属性/方法,会自动生成一个MI,格式:类名_MI
  2. @Module注释的类 + @Provides注释的方法,会自动生成多个Factory,格式:类名_方法名Factory
  3. @Inject注释的构造函数,会自动生成一个Factory,格式:类名_Factory
  4. @Component注释的接口,会自动生成一个实现类

--------------------------------------------

接下来,咱们再作一个正向分析,

  1. TodoApplication的tasksRepository增长注释@Inject,理解此步骤为标明依赖关系
  2. TasksRepository的构造函数增长注释@Inject
  3. AppComponent增长注释@Component
  4. Dagger自动生成的DaggerAppComponent,DaggerAppComponent负责注入

----------------------------------------------

紧接着从应用入口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之间的区别

------------------------------------

注:大神路过,多多指点!

相关文章
相关标签/搜索