Dagger 2 系列(三) -- 基礎篇:@Module 和 @Provides

leeGYPlus發表於2018-09-21

Dagger2

  • 該系列部落格的最終目標: 搭建 MVP + Dagger2 框架
  • 該系列部落格包含以下幾篇內容:
  1. Dagger 2 系列(一) -- 前奏篇:依賴注入的基本介紹
  2. Dagger 2 系列(二) -- 基礎篇:@Inject、@Component
  3. Dagger 2 系列(三) -- 基礎篇:@Module 和@Provides
  4. Dagger 2 系列(四) -- 基礎篇:@Named 和 @Qualifier
  5. Dagger 2 系列(五) -- 進階篇:@Scope 和 @Singleton

在這篇文章中你會看到什麼:

  • @Module 是什麼
  • @Provides 是什麼
  • @Module@Provides@Component 如何協同作戰。

1. 什麼是 Module

既然在Dagger 2 系列(二) -- 基礎篇:基本功能的實現一文中通過 @Inject@Component 我們已經實現了 DI,那麼為什麼 Dagger2 還要實現其他的DI 方式。

其實在上文中我們實現的 DI 方式中我們不難發現,通過@Inject 的註解實體類的建構函式是必不可少,它標識著 Dagger2 可以例項化該類。那麼當你需要例項化一個第三方的物件時,是不是懵逼了,因為你不可能註解第三方類的建構函式 -- 比如說 Gson 類的建構函式。那麼現在就需要 @Module 來充分發揮作用了。

其實Module 其實是一個簡單工廠模式,Module 裡面的方法都是建立相應類例項的方法。

具體什麼是 簡單工廠模式,請看程式碼段簡單學習設計模式 -- 簡單工廠模式

栗子:通過 @Module 的方式獲得第三方類庫的物件 -- Gson(當然也可以獲得自定義類物件)

@Module
public class AModule {

    @Provides
    public Gson provideGson(){
        return new Gson();
    }
}
複製程式碼

你再該類中看到了兩個註解:

  1. 通過 @Module 註解類
  2. 通過 @Provides 註解方法

1.2 新增多個 Module

一個 Component 可以含有多個 Module ,這樣在尋找依賴例項時就會自動從多個 Module 中尋找。

新增 多個 Module 的方法有兩種:

1.2.1 Component 註解 -- @Component(modules={××××,×××})

示例程式碼如下:

@Component(modules={ModuleA.class,ModuleB.class,ModuleC.class}) 
public interface AppComponent{
    ...
}
複製程式碼
1.2.2 Module 註解 -- @Module(includes={××××,×××})

示例程式碼如下:

@Module(includes={ModuleA.class,ModuleB.class,ModuleC.class})
public class FruitModule{
    ...
}
@Component(modules={FruitModule.class}) //新增多個Module
public interface AppComponent{
    ...
}
複製程式碼

這種使用 Moduleincludes 新增多Module 的方法一般用於構建更高層的Module時候使用,如在本例中

2. 什麼是 Provides

@Provides 用以標註 Module 類中的方法,它的作用是 標註該 Module 可以向外界提供的類的例項物件的方法 ,就像 AModule 中可以提供 Gson 例項物件的 provideGson() 方法。

3. Component -- 管理 Module

此時 DI 不是通過 @Inject 註解類構造器的方式,那麼這個註解器的使用方法肯定也有所變化。此時 Component 的職責是管理 Module,Component 中的屬性允許 Module 可以加入到 Component,同時一個 Component 可以加入多個 Module。

依賴注入的具體工作流程:

協作流程

若例項化過程中引數同樣是需要依賴注入的,那麼需要按照上圖中的流程一樣尋找相應的方法。如果遍歷了元件中管理的 Module 類中的 @Provides 註解的方法,那麼就會尋找該例項類的構造器中是否有被 @Inject 註解的,如果引數同樣有需要依賴注入的,那麼就重複以上過程。如果最終還是沒有找到相應的初始化例項的方法,那麼程式會報出相應的錯誤。

4. 程式碼示例

@Component(modules = UserTwoModule.class)
public interface UserTwoComponent {
    void injectToSecondActivity(SecondActivity mSecondActivity);
}

@Module
public class UserTwoModule {
    @Provides
    UserTwo provideUserTwo(){
        return new UserTwo("男",1243);
    }
}

public class SecondActivity extends AppCompatActivity {
    @Inject
    UserTwo mUserTwo;
    private static final String TAG = "SecondActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
     DaggerUserTwoComponent.builder().userTwoModule(new UserTwoModule()).build().injectToSecondActivity(this);
    }
}

複製程式碼

Dagger2sample github地址

總結

到此為止,我們已經實現了基本的基於Dagger2@Module@Provides的依賴注入。下面我們把過程再梳理一遍:

  1. 用@Inject註解標註目標類中其他類
  2. Module 中建立返回值為相應實體類的方法,並用 @Provides 標註
  3. 若其他類還依賴於其他的類,則重複進行上面2個步驟
  4. 呼叫Component(注入器)的injectXXX(Object)方法開始注入(injectXXX方法名字是官方推薦的名字,以inject開始)

Component 就像媒介,連線 Module目標類,把目標類依賴的例項注入到目標類中,來初始化目標類中的依賴。


參考資料

Dagger 詳解

這就是Dagger2

Dagger2 入門實踐

Android:dagger2讓你愛不釋手-終結篇

最簡單的Dagger2入門教程

Android:dagger2讓你愛不釋手-基礎依賴注入框架篇

相關文章