如果你已經閱讀了本文的第一部分,那么你應該對本項目的modules以及結構都比較清楚。現在我們繼續。。。
你能夠介紹一下Dagger怎么將core中的各個modules以及MVP的各個層連接在一起嗎?

Dagger2使用Modules,Components和SubComponents來知道需要注入什么以及怎么注入依賴。你可以找到很多介紹Dagger內部原理的文章。
Dagger示意圖中,從下往上我們可以看到CacheModule和SearchModule,兩者都分別提供了View和Presenter:
package com.mirhoseini.marvel.character.cache;
import dagger.Module;
import dagger.Provides;
@Module
class CacheModule {
private CacheView view;
CacheModule(CacheView view) {
this.view = view;
}
@Provides
public CacheView provideView() {
return view;
}
@Provides
@Cache
public CachePresenter providePresenter(CachePresenterImpl presenter) {
presenter.bind(view);
return presenter;
}
}
package com.mirhoseini.marvel.character.search;
import dagger.Module;
import dagger.Provides;
@Module
class SearchModule {
private SearchView view;
SearchModule(SearchView view) {
this.view = view;
}
@Provides
public SearchView provideView() {
return view;
}
@Provides
@Search
public SearchInteractor provideInteractor(SearchInteractorImpl interactor) {
return interactor;
}
@Provides
@Search
public SearchPresenter providePresenter(SearchPresenterImpl presenter) {
presenter.bind(view);
return presenter;
}
}
首先,請注意provide方法的返回類型,他們都是返回接口,而不是具體接口的實現!這就是為什么在后續的測試中我們可以替換掉具體的實現。我必須指出來這里是SOLID原則中開閉原則,里氏替換原則和依賴反轉原則的一個混合體。
其次,不要忘記我們現在還處于coremodule,我們還不知道View將怎么使用這些代碼。
最后,這兩個module被CacheSubComponent和SearchSubComponet使用,這兩個component是ApplicationComponent的子Component,稍后我將在appmodule中做介紹。
在core中有兩個module幫助我們提供Retrofit依賴,分別是ApiModule和ClientModule。熟悉Retrofit2將有助你理解這一部分的代碼,在本文的第三部分我也會做詳細的介紹。
所有這些module和DataBaseModule都被ApplicationComponent使用,這一部分我會在app module中介紹。
現在來看看使用Dagger后app module內部是什么樣子
appmodule中最重要的Dagger部分是:ApplicationComponent使用AndroidModule和ApplicationModule來提供所有的Application注入。
ApplicationComonent內容:
1.AndroidModule:
這個module提供了Application Context和Resources用于注入,在android開發中使用Context和Resources可以很方便的訪問到一系列Services和不同的Resources。有的開發者喜歡在ApplicationModule中實現這個module,但是我更喜歡將它獨立出來這樣會更加清晰。
這個module將在MarvelApplication中創建,MarvelApplication繼承自Application類:
package com.mirhoseini.marvel;
import android.app.Application;
public abstract class MarvelApplication extends Application {
private static ApplicationComponent component;
public static ApplicationComponent getComponent() {
return component;
}
@Override
public void onCreate() {
super.onCreate();
initApplication();
component = createComponent();
}
public ApplicationComponent createComponent() {
return DaggerApplicationComponent.builder()
.androidModule(new AndroidModule(this))
.build();
}
public abstract void initApplication();
}
你可能已經注意到這個類是一個抽象類,通過debug或者release編譯類型來實現initApplication()方法來完成,這對于在release版本或者debug版本中做一些不同的操作是非常方便的。
在這個實例中, 我通過debug版本的MarvelApplicationImpl來引入Timber庫,從而避免在release版本中輸出Timber log:
package com.mirhoseini.marvel;
import timber.log.Timber;
public class MarvelApplicationImpl extends MarvelApplication {
@Override
public void initApplication() {
// 在debug版本中初始化 Timber 用于log輸出
Timber.plant(new Timber.DebugTree() {
@Override
protected String createStackElementTag(StackTraceElement element) {
// 在log中輸出代碼行號
return super.createStackElementTag(element) + ":" + element.getLineNumber();
}
});
}
}
2.ApplicationModule:
這個module幾乎提供了所有的Application需求:
- isDebug:用BuildConfig.DEBUG來判斷當前運行的應用實例是否為debug模式,進而確定是否在log輸出中打印網絡API的信息。
- networkTimeoutInSeconds, cacheSize, cacheMaxAge, cacheMaxStale, cacheDir:提供為Retrofit創建OkHttp client時所需要的網絡參數。
- endpoint:為retrofit提供API的endpoint。
- appSchedule:提供RxAndroid調度者,詳細內容我將在RxJava部分介紹。
- isConnect:提供網絡狀態,用于處理離線情況。
3.ApiModule,ClientModule
4.DatabaseModule
5.subComponents:
Dagger的好處是可以添加SubComponent,你可以添加SubComponent到你的主ApplicationComponent,你可以添加你自己的注入內容,你也可以使用所有它提供的注入內容。
在此示例中,SearchSubComponent和CacheSubComponent添加到ApplicationComponent并使其更加出色。
SearchSubComponent 和 CacheSubComponent:
一起來看一下ApplicationComponent:
package com.mirhoseini.marvel;
/*...*/
@Singleton
@Component(modules = {
AndroidModule.class,
ApplicationModule.class,
ApiModule.class,
DatabaseModule.class,
ClientModule.class
})
public interface ApplicationComponent {
void inject(MainActivity activity);
SearchSubComponent plus(AppSearchModule module);
CacheSubComponent plus(AppCacheModule module);
}
如你所見,我們已經使用了inject方法用于注入,但是那些plus方法是什么鬼?!
首先,我需要指出inject和plus都只是名字!!你可以修改為任意你喜歡的名字,Dagger會檢查方法的輸入輸出從而確定它的用途。但是請不要讓你的團隊成員在以后閱讀這份代碼時找不著北。。。
使用plus方法你可以要求Dagger添加一個SubComponent到ApplicationComponent,并在相應的SubComponent中去實現inject方法。
plus方法使用Module作為參數,返回一個SubComponent,這個SubComponent使用的module為plus方法傳入的參數。
一起來仔細的看一下:
package com.mirhoseini.marvel.character.search;
import dagger.Subcomponent;
@Search
@Subcomponent(modules = {
AppSearchModule.class
})
public interface SearchSubComponent {
void inject(CharacterSearchFragment fragment);
}
好啦好啦,那么Dagger集成是從哪里開始的呢?
簡單的修改一下manifest,我們可以要求Android使用MarvelApplication的實現作為應用的入口:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.mirhoseini.marvel">
<!-- *** -->
<application
android:name=".MarvelApplicationImpl"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<!-- *** -->
</application>
</manifest>
我們一旦在MarvelApplication中創建了Application component,所有繼承自BaseActivity的Activity和繼承自BaseFragment的Fragment就可以使用了。BaseActivity和BaseFragment都是抽象類,他們的injectDependencies都必須在子類中實現。
怎樣學習更多的Dagger內容?!
如果你愿意,你可以學習跟多關于Dagger的內容。
可以閱讀一下這篇文章,這篇文章詳細介紹了怎么注入一切內容。。。。我在在樣例項目中,appmodule中的APPSearchModule和APPCacheModule分別繼承自core中的SearchModule和CacheModule。
請從github上clone一份代碼并熟悉一下,因為從下一部分我將更多的介紹retrofit以及它是怎么幫助我們使用網絡API調用以及緩存使用。
我期待您的意見和幫助以便更好的改進這篇文章。
繼續下一篇:MVP實踐(Android)-Part3:使用Retrofit調用API
原文鏈接:Yet another MVP article?—?Part 2: How Dagger helps with the project