Dagger2總結

簡單總結一下  方便日後查詢



     Dagger2是爲了解決對象依賴關係而生的依賴注入框架 目的是爲了降低代碼耦合   它會在編譯後自動爲被inject的類添加所需要new出對應對象的代碼
    

    用大白話說 
    就比如 

@Inject  
User user;  
@Override  
protected void onCreate(Bundle savedInstanceState) {  
    super.onCreate(savedInstanceState);  
    setContentView(R.layout.activity_c);  
    DaggerCActivityComponent.builder().cUserModule(new CUserModule()).build().inject(this);  
    TextView tv = (TextView) findViewById(R.id.tv);  
    tv.setText(user.toString());  
}  


    這裏先@inject User user 看到這個 意味着我們下面的代碼 等會如果哪裏要用到這個user 實例了 就不需要重新new了  Dagger2會在編譯的時候自動幫我們new出來


1引用


    
     在項目中引入Dagger2需要修改兩個地方的gradle文件,首先是project的gradle文件,修改成如下樣子:

dependencies {  
        classpath 'com.android.tools.build:gradle:2.1.0'  
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'  
  
        // NOTE: Do not place your application dependencies here; they belong  
        // in the individual module build.gradle files  
    }  





然後修改module的gradle文件:

apply plugin: 'com.neenbedankt.android-apt'  
dependencies {  
    compile fileTree(include: ['*.jar'], dir: 'libs')  
    testCompile 'junit:junit:4.12'  
    compile 'com.android.support:appcompat-v7:24.1.1'  
    compile 'com.google.dagger:dagger:2.6'  
    apt 'com.google.dagger:dagger-compiler:2.6'  
    compile 'com.squareup.picasso:picasso:2.5.2'  
}  






      這裏有幾個地方需要說一下,首先Dagger2我們可以直接在jCenter中搜索到的,可以搜到之後直接添加,那麼和Dagger2有關的是兩個文件:

compile 'com.google.dagger:dagger:2.6'  
apt 'com.google.dagger:dagger-compiler:2.6'  


    但是這兩個一個用了compile一個用了apt,使用apt表示該引用類庫只在編譯的時候起作用,在打包的時候並不會打包到apk中去。


2 @Module

    前面說了 只要用了@inject 標註一下依賴到的類 User 那麼Dagger2會在編譯後自動幫我們生成這個類的實例user,但Dagger2怎麼知道如何new 出一個User的實例呢? 需要我們自己定義一個類使用@Module標註  然後在這個Module類裏面 我們通過一個方法 
@Module  
public class UserModule {  
    @Provides  
    @Singleton  
    User providesUser() {  
        return new User();  
    }  
}  


 povidesUser() 方法返回了一個User對象


3 @Provides

     那麼當我爲這個Activity注入了user的依賴之後,Dagger會在被@Module註解的代碼裏尋找對應的返回值一致的方法,什麼代碼負責告訴Dagger2對應的類的生成方法呢?

     也就是說Dagger2自動生成的new出User類的那些代碼 在哪裏定義呢?
     就在Module裏被@Provides修飾的方法裏定義  


     這裏providersUser()方法剛好返回的是User對象  方法體很簡單就是new User();


   所以當Activity在用到User對象的時候,它就知道,我需要去Module裏找對應的生成方法了,找到對應的Module     後,再在Module裏找被@Provides修飾的方法,這個方法就爲Dragger2提供了構建新對象的具體方法



4@Component 


     看到了@Module和@provides之後 還有一個疑問 就是   我知道被inject之後 一旦需要用到它的實體  我會到modules裏面找  但Dagger2裏 modules並不止一個  

     事實上 Dagger2允許你自定義無窮多的Modules   只要一個類裏 有provides方法  然後被@Modules修飾 它就算是一個Module  。

     那麼多的Modules 如何告訴Dagger去那個裏面找 這就需要用到一個新的註解 叫做@Component  

 

     一個Component 就類似一個注射器   他把藥物 Modules 和 病人 (使用了依賴對象的類 比如這裏片頭的Activity )聯繫在了一起

     他的定義方式很簡單
@Singleton  
@Component(modules = UserModule.class)  
public interface ActivityComponent {  
    void inject(MainActivity activity);  
}  



   

  先用@Component註解修飾 告訴Dragger2這是一個組件(注射器),後面(modules=xxxModule.class , yyyModule.class...)告訴這個注射器可以打哪幾種藥物,組件都是接口,接口中定義了inject方法,這裏的inject方法中需要傳入一個病人對象,比如這裏傳入的是MainActivity ,這樣一來,一個注射器就定義好了,他把Modules和注入的對象聯繫在一起了,這裏可以定義多個帶有不同參數的jnject方法 比如

@UserScope  
@Component(modules = UserModule.class)  
public interface ActivityComponent {  
    void inject(MainActivity activity);  
  
    void inject(BActivity activity);  
}  




 這涉及到下面要說的 @scope註解了


5@scope

   顧名思義  他是用來定義作用域的


     前面用的@singleton 是系統自帶的一個scope 被它修飾的類它意味着在整個項目中只有一個實體 ,也就是全局單利  模式,在實際開發過程中,除了全局單例,更常見的是局部單例,比如

以下參考博主

http://blog.csdn.net/u012702547/article/details/52213706


    我們有三個Activity,MainActivity,BActivity和CActivity,我們想讓MainActivity和BActivity共享同一個實例,而讓CActivity獲取另外一個實例,這又該怎麼實現呢?在Dagger2中,我們可以通過自定義Scope來實現局部單例。

首先讓我們先來定義一個局部作用域:
 
@Scope  
@Retention(RetentionPolicy.RUNTIME)  
public @interface UserScope {  
}  



然後在我們的UserModule和ActivityComponent中應用該局部作用域:

@Module  
public class UserModule {  
    @Provides  
    @UserScope  
    User providesUser() {  
        return new User();  
    }  
}  





@UserScope  
@Component(modules = UserModule.class)  
public interface ActivityComponent {  
    void inject(MainActivity activity);  
  
    void inject(BActivity activity);  
}  




   請大家注意,我的ActivityComponent作爲一個注入器只可以向MainActivity和BActivity兩個Activity中注入依賴,不可以向CActivity中注入依賴。最後,要讓該局部作用域產生單例效果,需要我們在自定義的Appliation類中來初始化這個Component,如下:

public class MyApp extends Application {  
    ActivityComponent activityComponent;  
    @Override  
    public void onCreate() {  
        super.onCreate();  
        activityComponent = DaggerActivityComponent.builder().userModule(new UserModule()).build();  
    }  
  
    ActivityComponent getActivityComponent(){  
        return activityComponent;  
    }  
}  


接下來我們在MainActivity和BActivity中注入依賴,MainActivity如下:

    
@Inject  
    User user;  
    @Inject  
    User user2;  
    private TextView tv;  
    private TextView tv2;  
  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
//        DaggerActivityComponent.builder().userModule(new UserModule()).build().inject(this);  
        ((MyApp) getApplication()).getActivityComponent().inject(this);  
        tv = ((TextView) findViewById(R.id.tv));  
        tv2 = ((TextView) findViewById(R.id.tv2));  
        tv.setText(user.toString());  
        tv2.setText(user2.toString());  
    }  



BActivity如下:
  
@Inject  
User user;  
  
@Override  
protected void onCreate(Bundle savedInstanceState) {  
    super.onCreate(savedInstanceState);  
    setContentView(R.layout.activity_b);  
    ((MyApp) getApplication()).getActivityComponent().inject(this);  
    TextView tv = (TextView) findViewById(R.id.tv);  
    tv.setText(user.toString());  
}  



那麼如果我還想在CActivity中使用User對象該怎麼辦呢?再來一個CUserModule和CActivityComponent
CUserModule如下:

@Module  
public class CUserModule {  
    @Provides  
    User providesUser() {  
        return new User();  
    }  
}  


這裏沒有再著名單例

CActivityComponent如下:

@Component(modules = CUserModule.class)  
public interface CActivityComponent {  
    void inject(CActivity activity);  
}  



在CActivity中注入依賴:

@Inject  
User user;  
@Override  
protected void onCreate(Bundle savedInstanceState) {  
    super.onCreate(savedInstanceState);  
    setContentView(R.layout.activity_c);  
    DaggerCActivityComponent.builder().cUserModule(new CUserModule()).build().inject(this);  
    TextView tv = (TextView) findViewById(R.id.tv);  
    tv.setText(user.toString());  
}  



運行結果如下:


    可以看到,MainActivity和BActivity是同一個實例,而CActivity則是另外一個實例。
@UserScope在這裏到底起了什麼作用?我引用網上一段話:
以下文字來源:http://blog.csdn.net/u012943767/article/details/51941872


    Scope的使用,如何實現單例?  
  
這個迷之Scope也是有點難以理解,我們在哪裏使用到了Scope呢。在我們的AppComponent中添加了一個註解爲@Singleton,@Singleton就是一個Scope,據說可以實現單例喲。。。難道這樣就實現了單例模式?我剛剛開始是這樣理解的。直到仔細的看了幾遍這篇文章我才知道並不是這樣的。  
  
事實上@Sinleton中並沒有創建單例的能力,那麼AppComponent中提供的依賴注入是如何實現單例的呢。其實這個原理很賤單。  
  
首先Module提供了創建實例的方法,接着AppComponent中對Module進行管理,最後AppComponent在自定義Applicaiton中被實例化了一次。  
  
這個實例化了一次是最重要的呀。僅僅被實例化了一次,那不就是單例麼。就是這麼簡單呀。  
  
可能有些童靴當時就不樂意了,那既然這樣都已經實現了單例,那麼這個@Singltop還要來何用?不是多此一舉嗎。  
  
其實@Singletop還有有一些作用的,首先一方面能讓你直面的瞭解到這是一個單例,其次這個@Singletop能夠更好的管理Modlue和Component之間的關係。  
  
Dagger2需要保證Component和Module是匹配的,就需要用到這個註解。  




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章