[譯]MVP實踐(Android)-Part2:Dagger使用

如果你已經閱讀了本文的第一部分,那么你應該對本項目的modules以及結構都比較清楚。現在我們繼續。。。

你能夠介紹一下Dagger怎么將core中的各個modules以及MVP的各個層連接在一起嗎?

Dagger示意圖
Dagger示意圖

Dagger2使用ModulesComponentsSubComponents來知道需要注入什么以及怎么注入依賴。你可以找到很多介紹Dagger內部原理的文章。

Dagger示意圖中,從下往上我們可以看到CacheModuleSearchModule,兩者都分別提供了ViewPresenter

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被CacheSubComponentSearchSubComponet使用,這兩個component是ApplicationComponent的子Component,稍后我將在appmodule中做介紹。

core中有兩個module幫助我們提供Retrofit依賴,分別是ApiModuleClientModule。熟悉Retrofit2將有助你理解這一部分的代碼,在本文的第三部分我也會做詳細的介紹。

所有這些module和DataBaseModule都被ApplicationComponent使用,這一部分我會在app module中介紹。

現在來看看使用Dagger后app module內部是什么樣子

appmodule中最重要的Dagger部分是:ApplicationComponent使用AndroidModuleApplicationModule來提供所有的Application注入。

ApplicationComonent內容:

1.AndroidModule

這個module提供了Application ContextResources用于注入,在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,你可以添加你自己的注入內容,你也可以使用所有它提供的注入內容。

在此示例中,SearchSubComponentCacheSubComponent添加到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添加一個SubComponentApplicationComponent,并在相應的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,所有繼承自BaseActivityActivity和繼承自BaseFragmentFragment就可以使用了。BaseActivityBaseFragment都是抽象類,他們的injectDependencies都必須在子類中實現。

怎樣學習更多的Dagger內容?!

如果你愿意,你可以學習跟多關于Dagger的內容。

可以閱讀一下這篇文章,這篇文章詳細介紹了怎么注入一切內容。。。。我在在樣例項目中,appmodule中的APPSearchModuleAPPCacheModule分別繼承自core中的SearchModuleCacheModule

請從github上clone一份代碼并熟悉一下,因為從下一部分我將更多的介紹retrofit以及它是怎么幫助我們使用網絡API調用以及緩存使用。

我期待您的意見和幫助以便更好的改進這篇文章。

繼續下一篇:MVP實踐(Android)-Part3:使用Retrofit調用API

原文鏈接:Yet another MVP article?—?Part 2: How Dagger helps with the project

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容