Dagger 2 在 Android 上的使用(二)
本文介紹了Dagger 2 中@Inject、@Component、@Module和@Provides以及@Module和@Binds的使用。
本文首發:ofollow,noindex">http://yuweiguocn.github.io/
《七步詩》
煮豆燃豆萁,豆在釜中泣。
本是同根生,相煎何太急?
-兩漢,曹植
前言
Dagger 2 在 Android 上的使用(一)
在上一篇文章中我們介紹了Dagger2在android上的簡單用法,接下來我們對Dagger2中提供的註解進行詳細的使用說明。
註解@Inject和註解@Component
使用註解@Inject
和註解@Component
可以完成簡單依賴注入。
先來看一個未使用Dagger2的例子,稍候使用Dagger2完成依賴注入。
public class People { public String doWhat() { return "eat"; } }
在Activity中例項化此類並呼叫相應方法:
public class PeopleActivity extends Activity { private People people; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); people=new People(); Log.d("debug", people.doWhat()); } }
使用Dagger2完成依賴注入,People類需要新增一個空的構造方法並使用@Inject
進行註解:
public class People { @Inject public People() { } public String doWhat() { return "eat"; } }
註解@Inject
用在構造方法上表示告訴Dagger 2可以使用此構造方法提供需要的例項。
新增一個@Component
註解的介面類,這會生成以Dagger為字首的Component實現類。
註解@Component
只能用在介面或抽象類上。
@Component public interface PeopleComponent { void inject(PeopleActivity activity); }
在Activity中使用@Inject
對People進行註解,注意型別不能是private的
。然後編譯使用生成的DaggerPeopleComponent類進行依賴注入。
public class PeopleActivity extends Activity{ @Inject People people; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); DaggerPeopleComponent.create().inject(this); Log.d("debug", people.doWhat()); } }
然後我們看一下生成的類是如何實現依賴注入的。在Activity中的成員變數people新增的@Inject
註解生成了對應的MembersInjector類,用於給對應注入成員變數賦值。
public final class PeopleActivity_MembersInjector implements MembersInjector<PeopleActivity> { private final Provider<People> peopleProvider; public PeopleActivity_MembersInjector(Provider<People> peopleProvider) { this.peopleProvider = peopleProvider; } public static MembersInjector<PeopleActivity> create(Provider<People> peopleProvider) { return new PeopleActivity_MembersInjector(peopleProvider); } @Override public void injectMembers(PeopleActivity instance) { injectPeople(instance, peopleProvider.get()); } public static void injectPeople(PeopleActivity instance, People people) { instance.people = people; //完成賦值 } }
定義的Component介面類生成了對應的實現類,當我們在Activity中呼叫inject方法時完成了成員變數的賦值。
public final class DaggerPeopleComponent implements PeopleComponent { private DaggerPeopleComponent(Builder builder) {} public static Builder builder() { return new Builder(); } public static PeopleComponent create() { return new Builder().build(); } @Override public void inject(PeopleActivity activity) { injectPeopleActivity(activity); } private PeopleActivity injectPeopleActivity(PeopleActivity instance) { PeopleActivity_MembersInjector.injectPeople(instance, new People()); //進行成員變數的注入 return instance; } public static final class Builder { private Builder() {} public PeopleComponent build() { return new DaggerPeopleComponent(this); } } }
PS:從生成的程式碼中我們發現了一個People_Factory類用於People的例項化,但目前並沒有用到。
這樣我們使用註解@Inject
和註解@Component
就完成了簡單的依賴注入。
註解@Inject
是JSR-330標準中的一部分,標記那些應該被依賴注入框架提供的依賴。
註解@Inject
用在構造器上有兩種作用:
- 表示可以使用此構造器構建物件
- 注入構造器所需要的引數的依賴
例如People依賴Tools類,這樣也會完成Tools的注入。
public class People { private Tools tools; @Inject public People(Tools tools) { this.tools = tools; } } public class Tools { @Inject public Tools() { } public String getCar() { return "car"; } }
註解@Inject
可以用在成員變數完成依賴注入,正如上面看到的例子,也可以用在成員方法上完成依賴注入,例如:
public class PeopleActivity extends Activity{ private People people; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); DaggerPeopleComponent.create().inject(this); Log.d("debug", people.doWhat()); } @Inject public void setPeople(People people) { this.people = people; } }
然後我們再來看一下生成的程式碼:
public final class DaggerPeopleComponent implements PeopleComponent { private DaggerPeopleComponent(Builder builder) {} ... private People getPeople() { return new People(new Tools()); } @Override public void inject(PeopleActivity activity) { injectPeopleActivity(activity); } private PeopleActivity injectPeopleActivity(PeopleActivity instance) { PeopleActivity_MembersInjector.injectSetPeople(instance, getPeople()); return instance; } ... }
成員注入:
public final class PeopleActivity_MembersInjector implements MembersInjector<PeopleActivity> { ... public static void injectSetPeople(PeopleActivity instance, People people) { instance.setPeople(people); } }
從生成的程式碼來看使用成員變數注入和成員方法注入基本沒有任何區別,這兩者都是在呼叫注入方法時完成變數的賦值。推薦大家使用更簡單的成員變數注入方法。
註解@Module和註解@Provides
使用@Inject標註構造方法這種方式會有以下限制:
- 第三方庫無法注入
- 介面和抽象類無法注入
針對上述限制我們可以使用註解@Module
和註解@Provides
完成注入,接下來看一個抽象類和介面注入的例項:
public abstract class People { abstract String doWhat(); } public class Student extends People { @Override String doWhat() { return "study"; } } public class Worker extends People { @Override String doWhat() { return "work"; } }
新建Module類用於提供相應例項:
@Module public class PeopleModule { @Provides People providePeople() { //為抽象類提供例項 return new Student(); } @Provides PeopleContract.Presenter providePeoplePresenter(){ //為介面提供例項 return new PeoplePresenter(); } }
在Component類指定Module類:
@Component(modules = PeopleModule.class) public interface PeopleComponent { void inject(PeopleActivity activity); }
在Activity中進行注入:
public class PeopleActivity extends Activity{ @Inject People people; //抽象類的注入 @Inject PeopleContract.Presenter mPresenter; //介面的注入 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); DaggerPeopleComponent.create().inject(this); L.d(people.doWhat()); mPresenter.takeView(this); } }
Dagger2自動生成的類,用於提供People例項:
public final class PeopleModule_ProvidePeopleFactory implements Factory<People> { private final PeopleModule module; public PeopleModule_ProvidePeopleFactory(PeopleModule module) { this.module = module; } @Override public People get() { return provideInstance(module); } public static People provideInstance(PeopleModule module) { return proxyProvidePeople(module); } public static PeopleModule_ProvidePeopleFactory create(PeopleModule module) { return new PeopleModule_ProvidePeopleFactory(module); } public static People proxyProvidePeople(PeopleModule instance) { // 提供People的例項 return Preconditions.checkNotNull( instance.providePeople(), "Cannot return null from a non-@Nullable @Provides method"); } }
Dagger2自動生成的類,用於提供PeopleContract.Presenter例項:
public final class PeopleModule_ProvidePeoplePresenterFactory implements Factory<PeopleContract.Presenter> { private final PeopleModule module; public PeopleModule_ProvidePeoplePresenterFactory(PeopleModule module) { this.module = module; } @Override public PeopleContract.Presenter get() { return provideInstance(module); } public static PeopleContract.Presenter provideInstance(PeopleModule module) { return proxyProvidePeoplePresenter(module); } public static PeopleModule_ProvidePeoplePresenterFactory create(PeopleModule module) { return new PeopleModule_ProvidePeoplePresenterFactory(module); } public static PeopleContract.Presenter proxyProvidePeoplePresenter(PeopleModule instance) { return Preconditions.checkNotNull( instance.providePeoplePresenter(),//提供PeopleContract.Presenter例項 "Cannot return null from a non-@Nullable @Provides method"); } }
在Component類中進行了呼叫:
public final class DaggerPeopleComponent implements PeopleComponent { private PeopleModule peopleModule; private DaggerPeopleComponent(Builder builder) { initialize(builder); } public static Builder builder() { return new Builder(); } public static PeopleComponent create() { return new Builder().build(); } @SuppressWarnings("unchecked") private void initialize(final Builder builder) { this.peopleModule = builder.peopleModule; } @Override public void inject(PeopleActivity activity) { injectPeopleActivity(activity); } private PeopleActivity injectPeopleActivity(PeopleActivity instance) {//完成成員變數的注入 PeopleActivity_MembersInjector.injectPeople( instance, PeopleModule_ProvidePeopleFactory.proxyProvidePeople(peopleModule)); PeopleActivity_MembersInjector.injectMPresenter( instance, PeopleModule_ProvidePeoplePresenterFactory.proxyProvidePeoplePresenter(peopleModule)); return instance; } public static final class Builder { private PeopleModule peopleModule; private Builder() {} public PeopleComponent build() { if (peopleModule == null) { this.peopleModule = new PeopleModule(); } return new DaggerPeopleComponent(this); } public Builder peopleModule(PeopleModule peopleModule) { this.peopleModule = Preconditions.checkNotNull(peopleModule); return this; } } }
註解@Module和註解@Binds
對於抽象類和介面的注入,我們還可以使用註解@Binds
實現,使用註解@Binds
有如下要求:
- 必須用在Module裡的抽象方法
- 必須為抽象方法
- 必須有一個引數,引數型別可以分配給方法的返回型別
對上面的例子進行下修改:
@Module public abstract class PeopleModule { @Binds abstract People bindPeople(Student student); @Binds abstract PeopleContract.Presenter bindPeoplePresenter(PeoplePresenter presenter); }
這時我們需要給提供的注入型別新增空的構造方法,然後新增@Inject
註解:
public class Student extends People { @Inject public Student() { } @Override String doWhat() { return "study"; } } public class PeoplePresenter implements PeopleContract.Presenter { @Inject public PeoplePresenter() { } ... }
生成的程式碼;
public final class DaggerPeopleComponent implements PeopleComponent { private DaggerPeopleComponent(Builder builder) {} ... private PeopleActivity injectPeopleActivity(PeopleActivity instance) { PeopleActivity_MembersInjector.injectPeople(instance, new Student()); PeopleActivity_MembersInjector.injectMPresenter(instance, new PeoplePresenter()); return instance; } ... }
這可以實現和使用@Provides
註解相同的功能,這裡
推薦使用@Binds
註解實現注入功能
。
總結
-
使用註解
@Inject
和註解@Component
可以完成簡單的依賴注入 -
註解
@Component
只能用在介面或抽象類上,會自動生成以Dagger為字首的實現類 -
註解
@Inject
用在構造方法上表示可以使用此構造方法提供需要的例項,如果構造方法包含引數,也會對其引數完成注入 -
註解
@Inject
可以用在非private的成員變數和成員方法上完成依賴注入,推薦使用成員變數注入的方式 -
對於無法在構造方法上使用
@Inject
註解提供例項的情況,可以使用註解@Module
和註解@Provides
提供依賴例項,注意需要在Component類指定Module類 -
對於抽象類和介面的注入,也可以使用註解
@Module
和註解@Binds
實現,註解@Binds
用在抽象方法上,返回型別為需要注入的型別,包含一個可以分配給返回型別的引數, 推薦使用註解@Binds
完成依賴注入 ,注意需要在引數的構造方法上新增@Inject
註解以提供對應例項