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之間的區別

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

注:大神路過,多多指點!

相關文章
相關標籤/搜索