Android Dagger2 @Component的dependencies屬性用法

 一個Component可以通過dependencies依賴另一個Component,可以獲取到另一個Component提供的依賴

具體代碼如下:

public interface Person {
    String saySomething();
}

public class Student implements Person {

    public String name;

    public Student() {
        this.name = "野猿新一";
    }

    @Override
    public String saySomething() {
        return String.format("我的名字叫%s啦", name);
    }
}
@Module
public class PersonModule {
    @Provides
    public Person providePerson() {
        return new Student();
    }
}

 注意這裏爲Person單獨創建了一個Component然後依賴PersonModule,而不是直接把PersonModule設置給MainActivityModule

而且裏面的getPerson()方法單純提供Person對象,不像MainActivityModule中的inject()方法用於注入

@Component(modules = PersonModule.class)
public interface PersonComponent {
    Person getPerson();
}

 這裏有別於依賴於Module的寫法@Component(modules = PersonModule.class),而是直接依賴PersonComponent

@Component(dependencies = PersonComponent.class)
public interface MainActivityComponent {
    void inject(MainActivity activity);
}

 這裏需要注意的是personComponent()方法必須調用且傳遞一個PersonComponent對象進入,否則在運行時會報如下錯誤

實現代碼

Caused by: java.lang.IllegalStateException: com.him.hisapp.PersonComponent must be set
        at com.him.hisapp.DaggerMainActivityComponent$Builder.build(DaggerMainActivityComponent.java:45)
        at com.him.hisapp.MainActivity.onCreate(MainActivity.java:20)
        at android.app.Activity.performCreate(Activity.java:6041)
public class MainActivity extends AppCompatActivity {

    @Inject
    Person person;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        DaggerMainActivityComponent.builder()
                .personComponent(DaggerPersonComponent.create())
                .build()
                .inject(this);
        TextView textView = findViewById(R.id.text);
        textView.setText(person.saySomething());
    }
}

 DaggerMainActivityComponent源碼解析

我們主要看下Dagger爲我們生成的DaggerMainActivityComponent的源碼,裏面依賴了PersonComponent

在Builder.build()方法調用是會判斷personComponent是否爲空,空的話會拋異常,至於爲什麼不在爲空的時候直接new一個DaggerPersonComponent出來目前我還不知道原因,還請有知道的讀者評論說明下

public final class DaggerMainActivityComponent implements MainActivityComponent {
  private PersonComponent personComponent;

  private DaggerMainActivityComponent(Builder builder) {
    initialize(builder);
  }

  public static Builder builder() {
    return new Builder();
  }

  @SuppressWarnings("unchecked")
  private void initialize(final Builder builder) {
    this.personComponent = builder.personComponent;
  }

  @Override
  public void inject(MainActivity activity) {
    injectMainActivity(activity);
  }

  @CanIgnoreReturnValue
  private MainActivity injectMainActivity(MainActivity instance) {
    MainActivity_MembersInjector.injectPerson(
        instance,
        Preconditions.checkNotNull(
            personComponent.getPerson(),
            "Cannot return null from a non-@Nullable component method"));
    return instance;
  }

  public static final class Builder {
    private PersonComponent personComponent;

    private Builder() {}

    public MainActivityComponent build() {
      if (personComponent == null) {
        throw new IllegalStateException(PersonComponent.class.getCanonicalName() + " must be set");
      }
      return new DaggerMainActivityComponent(this);
    }

    public Builder personComponent(PersonComponent personComponent) {
      this.personComponent = Preconditions.checkNotNull(personComponent);
      return this;
    }
  }
}

注入的流程

我們再看下Dagger爲我們生成的代碼再注入的整個過程中做了哪些工作

首先從MainActivity中調用DaggerMainActivityComponent.inject()開始,記得必須調用personComponent設置依賴的Component

DaggerMainActivityComponent.builder()
                .personComponent(DaggerPersonComponent.create())
                .build()
                .inject(this);

 看下DaggerMainActivityComponent中的Builder代碼,卡夏是如何設置personComponent的和在build()的時候如果personComponent爲空會拋出異常

public static final class Builder {
    private PersonComponent personComponent;

    private Builder() {}

    public MainActivityComponent build() {
      if (personComponent == null) {
        throw new IllegalStateException(PersonComponent.class.getCanonicalName() + " must be set");
      }
      return new DaggerMainActivityComponent(this);
    }

    public Builder personComponent(PersonComponent personComponent) {
      this.personComponent = Preconditions.checkNotNull(personComponent);
      return this;
    }
  }

 DaggerMainActivityComponent的inject()方法內部調用了injectMainActivity()方法

@Override
public void inject(MainActivity activity) {
  injectMainActivity(activity);
}

 DaggerMainActivityComponent的injectMainActivity()方法內部調用了MainActivity_MembersInjector.injectPerson()方法來完成Person的依賴注入,傳入MainActivity對象和一個Person實例,而這個Person實例就是由PersonComponent的gerPerson()方法提供的

@CanIgnoreReturnValue
private MainActivity injectMainActivity(MainActivity instance) {
  MainActivity_MembersInjector.injectPerson(
      instance,
      Preconditions.checkNotNull(
          personComponent.getPerson(),
          "Cannot return null from a non-@Nullable component method"));
  return instance;
}

 我們在看下DaggerPersonComponent的getPerson()方法,裏面調用了PersonModule_ProvidePersonFactory.proxyProvidePerson()

@Override
public Person getPerson() {
  return PersonModule_ProvidePersonFactory.proxyProvidePerson(personModule);
}

 看下PersonModule_ProvidePersonFactory.proxyProvidePerson()方法內部就明白了Persong對象最終是由PersonModule提供的

public static Person proxyProvidePerson(PersonModule instance) {
  return Preconditions.checkNotNull(
      instance.providePerson(), "Cannot return null from a non-@Nullable @Provides method");
}

最終再看下MainActivity_MembersInjector.injectPerson()方法,裏面把生成的person對象賦值給MainActivity的person變量,最終完成依賴的注入

public static void injectPerson(MainActivity instance, Person person) {
  instance.person = person;
}

總結以上的注入流程就是

MainActivityComponent依賴PersonComponent

PersonComponent依賴PersonModule

所以最終的Person對象是由Module提供的

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章