上一篇:Android:Dagger2系列1 初識
下一篇:Android:Dagger2系列3 深入探究(更新ing)
這篇文章會分享一下實際應(yīng)用中的Dagger2如何使用,以及Dagger2通過apt插件如何給我們生成代碼照弥,以及生成的代碼之間的關(guān)聯(lián)键痛。
下面說一下模擬的業(yè)務(wù)場景:
主界面MainActivity通過MainPresenter去請求一個接口伶氢,并返回數(shù)據(jù)滑蚯。這里用的是MVP+Retrofit2+RxJava,如果不熟悉可以先不管,因為不會涉及太多克握,而這篇內(nèi)容主要分享的是Dagger2但校。
如果mvp不清楚的可以點擊 mvp google 寫法螃诅;RxJava和Retrofit后期我也會分享出來(知道的略過),歡迎關(guān)注W创选J趼恪!
先看下關(guān)于Dagger部分的包目錄結(jié)構(gòu):
google官方demo 是按照業(yè)務(wù)來分包的亭枷,個人比較喜歡按照組件來分袭艺。
首先我需要一個全局的網(wǎng)絡(luò)請求對象IRetrofitRequest放在Application,并且是單例的。所以寫了一個RetrofitModule提供IRetrofitRequest實例叨粘。
代碼塊1:
@Singleton
@Component(modules = {AppModule.class, RetrofitModule.class})
public interface AppComponent {
IRetrofitRequest request();
Context getContext();
}
其中request();方法返回的IRetrofitRequest對象需要上面代碼塊1:依賴的RetrofitModule類中進(jìn)行實例化:如下代碼
代碼塊2:
@Module
public class RetrofitModule {
@Provides
@Singleton
public IRetrofitRequest getService() {
OkHttpClient httpClient = new OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)//設(shè)置請求超時時間
.retryOnConnectionFailure(true)//設(shè)置出現(xiàn)錯誤進(jìn)行重新連接
.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標(biāo)注猾编,該對象是單例的所以用@Singleton標(biāo)注,這里為什么用這兩個注解標(biāo)注之后就能實現(xiàn)為AppComponent提供單例的實例宣鄙,稍后會進(jìn)行Dagger2生成的代碼解析袍镀。
當(dāng)然一個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注解標(biāo)注鼻弧。因為Dagger2需要這些標(biāo)注通過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是通過構(gòu)建者模式進(jìn)行初始化的。
.appModule(new AppModule(getApplicationContext()))
.retrofitModule(new RetrofitModule())
最后創(chuàng)建的AppComponent就提供了IRetrofitRequest全局單例對象码俩,整個app的網(wǎng)絡(luò)訪問都可以通過該對象進(jìn)行調(diào)用度帮。
AppComponent后期拓展:
一個全局的變量現(xiàn)在統(tǒng)一都可以放在AppComponent中進(jìn)行管理,這個demo中有網(wǎng)絡(luò)請求的一個單例接口對象,一個是全局的Context對象笨篷。后期肯定會有其他的都可以放在AppModule中進(jìn)行實例化瞳秽,或者單獨再寫一個Module依賴到AppComponent中。
在MainActivity中如何進(jìn)行使用:
這里用的是mvp開發(fā)模式率翅,所以需要一個Presenter:MainActivityPresenter练俐,需要傳遞一個參數(shù),用于操作MainActivity界面:MainActivityContract.View冕臭,而這個MainActivityPresenter誰來提供呢腺晾?當(dāng)然是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,你會發(fā)現(xiàn)我們在MainActivityModule 里提供了MainActivityPresenter實例悯蝉,但是在MainActivityComponent接口里并沒有寫上提供MainActivityPresenter的方法,另外還多了一個void inject(MainActivity mainactivity),這里跟AppComponent中的(代碼塊1)有區(qū)別是咋回事念颈?等會解釋泉粉。
再看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()中調(diào)用的抽象方法
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()中調(diào)用的抽象方法。
注意看代碼中的
@Inject
MainActivityPresenter presenter;
注意1:但是在整個MainActivity中卻找不到初始化的過程榴芳,再看providers()方法中的代碼嗡靡,跟App中有區(qū)別的是,我這里并沒有寫成
MainActivityComponent mainActivityComponent = DaggerMainActivityComponent.builder()
.mainActivityModule(new MainActivityModule(this))
.appComponent(App.getComponent())
.build();
注意2:還有的區(qū)別是多了一個
.inject(this);
原因:
1:因為在App中我并沒有哪個對象的聲明用了@Inject注解進(jìn)行標(biāo)注窟感,而且App中的AppComponent實例對象需要給其他Activity或者類使用讨彼。
2:在該demo中的MainActivity,我們不需要其他地方用到MainActivityComponent對象柿祈,我們只是在MainActivity用到MainPresenter對象哈误,我們可以不用通過MainActivityComponent中的某一個方法獲得MainPresenter對象,我們在用@Inject標(biāo)注MainActivityPresenter presenter的時候需要把在哪里聲明的外部類(這里是MainActivity)注入到MainComponent中躏嚎,就是上面(代碼塊5)說過的沒有提供返回MainPresenter的方法卻多了一個void inject(MainActivity mainactivity)蜜自;這里的返回值是void的inject方法名可以是任意的,但是最好寫成inject(官方寫法)卢佣。
最后只要調(diào)用了providers()方法重荠,我們的MainPresenter presenter對象就已經(jīng)被初始化了,這個時候就可以通過presenter.start()去調(diào)用網(wǎng)絡(luò)接口請求數(shù)據(jù)了虚茶;
只要我們配置了以上的Component,Module戈鲁,編譯之后Dagger2就會通過apt插件生成一系列代碼。
那么一系列代碼到底是怎樣的嘹叫?到底是怎樣工作的呢婆殿?
先看下生成的代碼目錄結(jié)構(gòu):
可以看到生成的代碼包名還是跟自己代碼中的一樣,生成的代碼的類名也有一定的規(guī)則罩扇。
看看這些代碼是根據(jù)什么注解生成的:
- 用@Component注解標(biāo)注的xxxComponent類會生成DaggerxxxComponent類
- 用@Module注解標(biāo)注的xxxModule中用@Provides注解標(biāo)注的每個方法都會生成一個類婆芦,這個類是一個工廠模式,提供對象實例,比如:
@Module
public class AAModule{
@ActivityScope
@Providespublic
BB getBB() {
return new BB();
}
}
getBB()方法就會生成AAModule_GetBBFactory類消约。
- 如果一個類的構(gòu)造函數(shù)用了@Inject注解標(biāo)注:例如:
public class CC{
@Inject
public CC() {
}
}
就會生成CC_Factory類癌压。
- 如果一個類中有用@Inject注解標(biāo)注對象聲明他就會生成:比如demo中的MainActivity;
public class MainActivity extends BaseActivity implements MainActivityContract.View {
@Inject
MainActivityPresenter presenter;
}
Dagger2就會自動生成MainActivity_MembersInjector。
看看這些代碼之間的關(guān)聯(lián)
分析圖箭頭的結(jié)尾是DaggerMainActivityComponent荆陆,也就是最后暴露給我們的就是DaggerMainActivityComponent這個類滩届,其它幫助我們生成的代碼都可以不用關(guān)心。
分析圖或許會有疏漏和不對被啼,基本情況應(yīng)該就是這樣帜消,更多細(xì)節(jié)性的代碼可以查看項目gitlab: demo
上一篇:Android:Dagger2系列1 初識
下一篇:Android:Dagger2系列3 深入探究(更新ing)