上一篇:Android:Dagger2系列1 初識
下一篇:Android:Dagger2系列3 深入探究(更新ing)
這篇文章會分享一下實際應用中的Dagger2如何使用,以及Dagger2通過apt插件如何給我們生成代碼,以及生成的代碼之間的關聯。
下面說一下模擬的業務場景:
主界面MainActivity通過MainPresenter去請求一個接口,并返回數據。這里用的是MVP+Retrofit2+RxJava,如果不熟悉可以先不管,因為不會涉及太多,而這篇內容主要分享的是Dagger2。
如果mvp不清楚的可以點擊 mvp google 寫法;RxJava和Retrofit后期我也會分享出來(知道的略過),歡迎關注?。。?/p>
先看下關于Dagger部分的包目錄結構:
google官方demo 是按照業務來分包的,個人比較喜歡按照組件來分。
首先我需要一個全局的網絡請求對象IRetrofitRequest放在Application,并且是單例的。所以寫了一個RetrofitModule提供IRetrofitRequest實例。
代碼塊1:
@Singleton
@Component(modules = {AppModule.class, RetrofitModule.class})
public interface AppComponent {
IRetrofitRequest request();
Context getContext();
}
其中request();方法返回的IRetrofitRequest對象需要上面代碼塊1:依賴的RetrofitModule類中進行實例化:如下代碼
代碼塊2:
@Module
public class RetrofitModule {
@Provides
@Singleton
public IRetrofitRequest getService() {
OkHttpClient httpClient = new OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)//設置請求超時時間
.retryOnConnectionFailure(true)//設置出現錯誤進行重新連接
.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(UrlConst.URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.client(httpClient)
.build();
return retrofit.create(IRetrofitRequest.class);
}
}
代碼塊2:中提供的IRetrofitRequest 實例對象必須要用@Provides標注,該對象是單例的所以用@Singleton標注,這里為什么用這兩個注解標注之后就能實現為AppComponent提供單例的實例,稍后會進行Dagger2生成的代碼解析。
當然一個Component類可以依賴多個Module,如代碼塊1:中還依賴了AppModule,AppModule中提供了在Component方法名是getContext()的實例對象,如下代碼:
代碼塊3:
@Module
public class AppModule {
private Context context;
public AppModule(Context context) {
this.context = context;
}
@Provides
public Context getContext() {
return context;
}
}
如代碼塊2和3所示,所有的被Component依賴的Module都必須用@Module注解標注。因為Dagger2需要這些標注通過apt插件自動生成代碼。
在AppComponent中提供的IRetrofitRequest單例對象如何在Application中使用呢?
代碼塊4:
public class App extends Application {
private static AppComponent appComponent;
@Override
public void onCreate() {
super.onCreate();
appComponent = DaggerAppComponent.builder()
.appModule(new AppModule(getApplicationContext()))
.retrofitModule(new RetrofitModule())
.build();
}
public static AppComponent getComponent() {
return appComponent;
}
}
代碼塊4:中的DaggerAppComponent是Dagger2幫我們自動生成的,只要編譯一下就可以自動生成:
AppComponent需要初始化依賴的兩個Module(AppModule和RetrofitModule),這里生成的DaggerAppComponent是通過構建者模式進行初始化的。
.appModule(new AppModule(getApplicationContext()))
.retrofitModule(new RetrofitModule())
最后創建的AppComponent就提供了IRetrofitRequest全局單例對象,整個app的網絡訪問都可以通過該對象進行調用。
AppComponent后期拓展:
一個全局的變量現在統一都可以放在AppComponent中進行管理,這個demo中有網絡請求的一個單例接口對象,一個是全局的Context對象。后期肯定會有其他的都可以放在AppModule中進行實例化,或者單獨再寫一個Module依賴到AppComponent中。
在MainActivity中如何進行使用:
這里用的是mvp開發模式,所以需要一個Presenter:MainActivityPresenter,需要傳遞一個參數,用于操作MainActivity界面:MainActivityContract.View,而這個MainActivityPresenter誰來提供呢?當然是Component通過依賴的Module來提供,看看MainActivity的Component和Module。
代碼塊5:
@ActivityScope
@Component(dependencies = AppComponent.class, modules = {MainActivityModule.class})
public interface MainActivityComponent {
void inject(MainActivity mainActivity);
}
代碼塊6:
@Module
public class MainActivityModule {
private MainActivityContract.View view;
public MainActivityModule(MainActivityContract.View view) {
this.view = view;
}
@ActivityScope
@Provides
public MainActivityPresenter getMainActivityPresenter() {
return new MainActivityPresenter(view);
}
}
這里的代碼塊5和6,你會發現我們在MainActivityModule 里提供了MainActivityPresenter實例,但是在MainActivityComponent接口里并沒有寫上提供MainActivityPresenter的方法,另外還多了一個void inject(MainActivity mainactivity),這里跟AppComponent中的(代碼塊1)有區別是咋回事?等會解釋。
再看MainActivity代碼:
代碼塊6:
public class MainActivity extends BaseActivity implements MainActivityContract.View {
@Inject
MainActivityPresenter presenter;
@Inject
SecondActivityPresenter secondActivityPresenter;
@Bind(R.id.textView)
TextView textView;
@Bind(R.id.textView2)
TextView textView2;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
presenter.start();
secondActivityPresenter.set();
}
@Override
public void providers() {//該方法是BaseActivity中onCreate()中調用的抽象方法
DaggerMainActivityComponent.builder()
.mainActivityModule(new MainActivityModule(this))
.appComponent(App.getComponent())
.build()
.inject(this);
}
@OnClick({R.id.textView, R.id.textView2})
public void onClick(View view) {
switch (view.getId()) {
case R.id.textView:
startActivity(new Intent(this, SecondActivity.class));
break;
case R.id.textView2:
break;
default:
break;
}
}
@Override
public void showSuccess() {
T.show(this, "成功");
}
@Override
public void showFailed() {
T.show(this, "失敗");
}
}
先解釋一下providers()方法:該方法是BaseActivity中onCreate()中調用的抽象方法。
注意看代碼中的
@Inject
MainActivityPresenter presenter;
注意1:但是在整個MainActivity中卻找不到初始化的過程,再看providers()方法中的代碼,跟App中有區別的是,我這里并沒有寫成
MainActivityComponent mainActivityComponent = DaggerMainActivityComponent.builder()
.mainActivityModule(new MainActivityModule(this))
.appComponent(App.getComponent())
.build();
注意2:還有的區別是多了一個
.inject(this);
原因:
1:因為在App中我并沒有哪個對象的聲明用了@Inject注解進行標注,而且App中的AppComponent實例對象需要給其他Activity或者類使用。
2:在該demo中的MainActivity,我們不需要其他地方用到MainActivityComponent對象,我們只是在MainActivity用到MainPresenter對象,我們可以不用通過MainActivityComponent中的某一個方法獲得MainPresenter對象,我們在用@Inject標注MainActivityPresenter presenter的時候需要把在哪里聲明的外部類(這里是MainActivity)注入到MainComponent中,就是上面(代碼塊5)說過的沒有提供返回MainPresenter的方法卻多了一個void inject(MainActivity mainactivity);這里的返回值是void的inject方法名可以是任意的,但是最好寫成inject(官方寫法)。
最后只要調用了providers()方法,我們的MainPresenter presenter對象就已經被初始化了,這個時候就可以通過presenter.start()去調用網絡接口請求數據了;
只要我們配置了以上的Component,Module,編譯之后Dagger2就會通過apt插件生成一系列代碼。
那么一系列代碼到底是怎樣的?到底是怎樣工作的呢?
先看下生成的代碼目錄結構:
可以看到生成的代碼包名還是跟自己代碼中的一樣,生成的代碼的類名也有一定的規則。
看看這些代碼是根據什么注解生成的:
- 用@Component注解標注的xxxComponent類會生成DaggerxxxComponent類
- 用@Module注解標注的xxxModule中用@Provides注解標注的每個方法都會生成一個類,這個類是一個工廠模式,提供對象實例,比如:
@Module
public class AAModule{
@ActivityScope
@Providespublic
BB getBB() {
return new BB();
}
}
getBB()方法就會生成AAModule_GetBBFactory類。
- 如果一個類的構造函數用了@Inject注解標注:例如:
public class CC{
@Inject
public CC() {
}
}
就會生成CC_Factory類。
- 如果一個類中有用@Inject注解標注對象聲明他就會生成:比如demo中的MainActivity;
public class MainActivity extends BaseActivity implements MainActivityContract.View {
@Inject
MainActivityPresenter presenter;
}
Dagger2就會自動生成MainActivity_MembersInjector。
看看這些代碼之間的關聯
分析圖箭頭的結尾是DaggerMainActivityComponent,也就是最后暴露給我們的就是DaggerMainActivityComponent這個類,其它幫助我們生成的代碼都可以不用關心。
分析圖或許會有疏漏和不對,基本情況應該就是這樣,更多細節性的代碼可以查看項目gitlab: demo
上一篇:Android:Dagger2系列1 初識
下一篇:Android:Dagger2系列3 深入探究(更新ing)