Dagger 2 在 Android 上的使用(五)
本文介紹了Dagger 2 中@Scope和@Subcomponent的使用。
本文首發:http://yuweiguocn.github.io/
《清明》
清明時節雨紛紛,路上行人慾斷魂。
借問酒家何處有,牧童遙指杏花村。
-唐,杜牧
生命週期
我們可以使用註解@Scope
來管理依賴的生命週期。它和註解@Qualifier
一樣是用來自定義註解的,註解@Scope
的預設實現是@Singleton
,用於在Component例項中保持單例。如果我們在Application類中持有Component的引用,就實現了應用內保持單例。
注意需要在Component上和提供例項的方法上同時新增@Scope
註解才會起作用
。接下來看一個使用的例子:
首先需要在Component類添加註解@Singleton
:
@Singleton @Component(modules = PeopleModule.class) public interface PeopleComponent { void inject(PeopleActivity activity); }
然後在Module類提供例項的方法上也需要添加註解@Singleton
:
@Module public abstract class PeopleModule { @Binds @Study @Singleton abstract People bindStudent(Student student); }
在Activity中同時注入兩個成員變數:
public class PeopleActivity extends Activity { @Inject @Study People student; @Inject @Study People student2; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); DaggerPeopleComponent.create().inject(this); Log.d("debug", student.toString()); Log.d("debug", student2.toString()); } }
可以看到注入了兩個變數,是同一個例項,列印日誌輸出:
2018-12-12 17:57:50.287 30809-30809/io.github.yuweiguocn.dagger D/debug: 1io.github.yuweiguocn.dagger.test.Student@be59fd9 2018-12-12 17:57:50.287 30809-30809/io.github.yuweiguocn.dagger D/debug: 2io.github.yuweiguocn.dagger.test.Student@be59fd9
生成的程式碼:
public final class DaggerPeopleComponent implements PeopleComponent { private Provider<People> bindStudentProvider; private DaggerPeopleComponent(Builder builder) { initialize(builder); } ... @SuppressWarnings("unchecked") private void initialize(final Builder builder) { this.bindStudentProvider = DoubleCheck.provider((Provider) Student_Factory.create()); } ... private PeopleActivity injectPeopleActivity(PeopleActivity instance) { PeopleActivity_MembersInjector.injectStudent(instance, bindStudentProvider.get()); PeopleActivity_MembersInjector.injectStudent2(instance, bindStudentProvider.get()); return instance; } ... }
這裡和Lazy注入一樣,都是使用DoubleCheck類保證了例項的唯一 。
通常我們會根據例項的生命週期自定義Scope,例如:ApplicationScope、ActivityScope和FragmentScope等。
註解@Subcomponent
Component類只能應用一個@Scope
註解,如果我們想使用多個@Scope
註解時,可以使用@SubComponent
實現,使用Subcomponent的另一原因是用於拆分層級。
首先自定義兩個Scope:
@Scope @Retention(RetentionPolicy.RUNTIME) public @interface AppScope { } @Scope @Retention(RetentionPolicy.RUNTIME) public @interface ActivityScope { }
然後使用@Subcomponent
註解定義兩個子元件,新增自定義的@ActivityScope
註解,指定Module類,提供Activity的注入方法:
@ActivityScope @Subcomponent(modules = WorkerModule.class) public interface WorkerComponent { void inject(WorkerActivity activity); } @ActivityScope @Subcomponent(modules = StuModule.class) public interface StuComponent { void inject(StuActivity activity); }
在父元件中暴露子元件,新增自定義的@AppScope
註解,注意
子元件不能與父元件應用相同的@Scope
註解
,子元件的生命週期嚴格小於父元件的生命週期,兄弟元件可以使用相同的@Scope
註解(但實際上具有不同的生命週期例項):
@AppScope @Component public interface PeopleComponent { StuComponent student(); WorkerComponent teacher(); @Component.Builder interface Builder{ PeopleComponent build(); @BindsInstance Builder application(Application application); } }
在子元件指定的Module中提供例項的方法上新增自定義的@ActivityScope
註解:
@Module public abstract class StuModule { @Binds @ActivityScope abstract People bindStudent(Student student); } @Module public abstract class WorkerModule { @Binds @ActivityScope abstract People bindWroker(Worker worker); }
在子元件指定的Module提供的例項新增對父元件提供例項的依賴:
public class Student extends People { private Application app; @Inject public Student(Application app) { this.app = app; } @Override String doWhat() { return "study app: " + app.toString(); } } public class Worker extends People { private Application app; @Inject public Worker(Application app) { this.app = app; } @Override String doWhat() { return "work app: " + app.toString(); } }
在Application中構建父元件:
public class App extends Application { private static App app; private PeopleComponent component; @Override public void onCreate() { super.onCreate(); app = this; component = DaggerPeopleComponent.builder().application(this).build(); } public static App getApp() { return app; } public PeopleComponent getComponent() { return component; } }
最後在Activity中使用Application構建的父元件中提供的子元件進行注入:
public class StuActivity extends Activity { @Inject Student student; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); App.getApp().getComponent().student().inject(this); Log.d("debug", student.doWhat()); } } public class WorkerActivity extends AppCompatActivity { @Inject Worker worker; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); App.getApp().getComponent().teacher().inject(this); Log.d("debug", worker.doWhat()); } }
總結
-
可以使用註解
@Scope
管理依賴的生命週期,@Scope
的預設實現是@Singleton
,可以在Component中保持單例,需要在Component上和提供例項的方法上同時添加註解才會起作用。原理是通過DoubleCheck類保證了例項的唯一。通常使用多個@Scope
時會根據例項生命週期自定義,如:AppScope、ActivityScope、FragmentScope等。 -
Component類只能應用一個
@Scope
註解,如果需要使用多個@Scope
,可以使用@Subcomponent
實現,使用@Subcomponent
的另一原因是用於拆分層級。 -
子元件Subcomponent不能和父元件使用相同的
@Scope
註解,子元件的生命週期嚴格小於父元件的生命週期,兄弟元件可以使用相同的@Scope
註解(但實際上具有不同生命週期的例項)。