Dagger2的使用

 

 

想學習下Dagger2 ,搜了不少資料但都是附帶着RxJava等其餘東西,讓樓主學習起來比較費時(可能比較笨),本人也沒有使用過Dagger1.x,因此學習Dagger2的更是舉步維艱啊。 html

看了不少資料,終於懂了一點,下面主要說說Dagger2的使用過程及本身看法,加深印象。說的不對的也請讀者指正。android

 

Dagger2是Android的一個依賴注入框架,可用於模塊間解耦,提升代碼的健壯性和可維護性。app

Dagger2是基於一個有向無環圖結構的依賴注入庫,所以dagger2的使用過程當中不能出現循環依賴的現象。框架

如下都已 Android studio開發工具爲例。ide

1、引用

在module的build.gradle添加以下兩個模塊 :函數

a、apply plugin: 'com.neenbedankt.android-apt'工具

b、compile 'com.google.dagger:dagger:2.5'學習

compile 'com.google.dagger:dagger-compiler:2.5'開發工具

在project的build.gradle中dependencies 添加gradle

classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4'

如:

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4'
    }
}
apt相關的依賴必定要加上,要不生成不了對應所需文件 Dagger+"" 等。

二、Component和Module  

Dagger2 經過註解來工做,定義不一樣的角色,主要的註解包括:@Component 、@Module 、@Inject、@Provides 、@Scope 、@SubComponent 等。

Component和Module是Dagger2的兩個主要註解。

module是生產對象的地方,便是生產方,須要什麼樣的對象都要在這裏生產

Component 是聯繫module和module使用場景的橋樑,module生產的對象須要在哪裏使用要靠Component來提供、暴露,即提供方。使module和module的使用場景達到了一個解耦。

dagger2的使用

模擬一個場景,類A須要在DaggerActivity使用 。

正常狀況:

A類 :

public class A {

    private int age;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

DaggerActivity :

public class DaggerActivity extends Activity {

    private static final String TAG = "DaggerActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityComponent aComponenet = DaggerActivityComponent.builder()
                .aModule(new AModule())
                .build();
        A a = new A();
        a.setAge(10);
        Log.d(TAG, "onCreate --> a.getAge() : : " + a.getAge());  a.setAge();   

    }
}

使用Dagger2:

A類 :

public class A {

    private int age;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

增長一個Module , AModule類 :

@Module
public class AModule {


    @Provides
    A provideA() {
        return new A();
    }
}

Module 類須要使用@Module註解,標記這是一個生產對象的地方,這裏僅生產了對象 A。

增長一個Component ,AComponent類 :

@Component(modules = AModule.class)
public interface AComponent{

    A a();
}

Component類須要使用@Component註解,並添加modules依賴,標記提供哪些對象,爲哪些Module提供橋樑 。modules能夠提供多個,寫法是 modules = {AModule.class,A2Module.class}等。Component也能夠依賴其它Component,實現@Component(dependencies = {A2Component.class,A3Component.class} modules = {AModule.class, A2Module.class})

使用,DaggerActivity :

public class DaggerActivity extends Activity {

    private static final String TAG = "DaggerActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        AComponentaComponenet = DaggerAComponent.builder()
                .aModule(new AModule())
                .build();

        A a = aComponenet.a();
        a.setAge(10);

       
    }
}

這樣就基本實現了Dagger2的使用,但咱們發現這時並無達到很好的解耦效果。下面再介紹兩種優化 :

使用Dagger2  二 :

使用@Inject註解 

A2 類 :

public class A2 {
    private int age;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

基本沒變化 

A2Module :

@Module
public class A2Module {

    @Provides
    A2 povideA2() {
        return new A2();
    }

}

A2Component :

@Component(modules = A2Module.class)
public interface A2Component {
    void inject(DaggerActivity mainActivity);
}

這裏多了一個inject()方法,參數爲提供A2實例的地方,即便用場景。相比AComponent主動暴露A實例的方式,解耦了一些。

使用

DaggerActivity  :

public class DaggerActivity extends Activity {

    private static final String TAG = "DaggerActivity";

    @Inject
    A2 aaa2;

 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    

        DaggerA2Component.builder()
                .a2Module(new A2Module())
                .build()
                .inject(this);


        aaa2.setAge(20);
        aaa2.getAge();
        Log.d(TAG, "onCreate --> aaa2.getAge() : : " + aaa2.getAge());

      
    }
}

這裏看到 經過@Inject 註解來能達到實例化 A2對象的目的。DaggerA2Component的inject()就是告訴Dagger2在哪裏實例化A2對象,這裏是在DaggerActivity,並將對象賦給aaa2引用。 解耦更完全了一些 。

還能更簡化一些嗎 ??   

Dagger2   三 :

A3類 :

public class A3 {

    @Inject
    public A3() {
    }

    private int age;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

注意這裏 在A3的構造函數上使用了 @Inject註解 。

A3Module 能夠沒有 

那麼 A3Component也就沒有了。 .(沒有橋頭,要橋樑幹麼呢)

使用  DaggerActivity 

public class DaggerActivity extends Activity {

    private static final String TAG = "DaggerActivity";


    @Inject
    A3 aaa3;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
       
        aaa3.setAge(30);
        aaa3.getAge();
        Log.d(TAG, "onCreate --> aaa3.getAge() : : " + aaa3.getAge());

    }
}

這裏A3的初始化經過@Inject註解來實現,但並無經過Component來告訴Dagger2在哪裏實例化A3並賦值給誰。 這主要依賴在A3的構造函數中添加了@Inject註解,當須要實例化一個@Inject註解的對象時,就去遍從來實例化對應的對象。

這樣解耦工做徹底實現了。

看完示例三,能夠發現Dagger2的優點徹底體現出來了吧。

經過上面的實例能夠發現示例三比示例二更簡潔,那麼Module註解是否是能夠不要了呢 ? 

何時使用Module,何時使用@Inject

通常系統的 、SDK的、第三方庫提供的對象用Module   (你無法在人家的構造函數上添加@Inject啊)

自定義的對象用Inject    定義一個子類繼承系統、SDK、第三方庫的對象,這時也可使用Inject。

Component間的依賴 

依賴一個Component時父Component須要將提供的對象暴露出來,不然子Component獲取不到

@Component(modules = {AModule.class, A2Module.class})
public interface AComponent {

    A a();
}
@Component(dependencies = AComponent.class, modules = A2Module.class)
public interface A2Component {
    void inject(DaggerActivity mainActivity);
}

AComponent暴露了A對象,這樣A2Component才能獲取到A。

@Scope註解

這個註解是用來劃分做用域的(在哪兒使用,使用範圍),意思是畫出一塊區域來,生產的東西若是限定在此做用域,那都放到這裏,做用域的場景類(如Activity、Fragment、Application)若是須要這個實例,就來這個做用域來取,有就直接使用,沒有就先建立,放到做用域供下次使用。

dagger2自已有個@Scope註解,叫@Singleton,就是你們都熟悉的單例模式

能夠自定義@Scope註解,好比限定生產出的某個對象只能在Activity中、Application中使用、Fragment中使用等等。。

定義一個Activity做用域的註解 

@Scope
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface PerActivity {
}
PerActivity的使用
public class A2 {

    private int age;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

public class A3 {

    @Inject
    public A3() {
    }

    private int age;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}


public class A4 {

    @Inject
    public A4() {
    }

    private int age;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

 

@Module
public class A2Module {

    @Named("李四")
    @Provides
    A2 povideALisi() {
        return new A2(21);
    }

    @Named("張三")
    @Provides
    A2 povideAZhangSan() {
        return new A2(25);
    }

    @PerActivity
    @Provides
    A4 provideA4() {
        return new A4();
    }

    @Provides
    A3 provideA3() {
        return new A3();
    }

}

注意這裏只給 provideA4()方法添加了@PerActivity註解 。

@PerActivity
@Component(dependencies = ActivityComponent.class, modules = A2Module.class)
public interface A2Component {
    void inject(DaggerActivity mainActivity);
}

 依賴A2Module的對應Component也要添加@PerActivity註解。

public class DaggerActivity extends Activity {

    private static final String TAG = "DaggerActivity";

    @Inject
    A4 aaa4;

    @Inject
    A4 testa4;

    private Button nextBtn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.dagger_layout);

        DaggerA2Component.builder()
                .a2Module(new A2Module())
                .build()
                .inject(this);
    

        aaa4.setAge(30);
        Log.d(TAG, "onCreate --> aaa4.getAge() : : " + aaa4.getAge());
        Log.d(TAG, "onCreate --> testa4.getAge() : : " + testa4.getAge());

        testa4.setAge(50);

        Log.d(TAG, "onCreate --> 2 aaa4.getAge() : : " + aaa4.getAge());
        Log.d(TAG, "onCreate --> 2 testa4.getAge() : : " + testa4.getAge());
        Log.d(TAG, "onCreate ------------------------------------------>  : ");

    }
}

能夠發現這時aaa4和testa4兩個對象會相互影響,改變一個,另外一個也被修改,其實爲同一個對象,爲何會這樣呢?? 

咱們來看下Dagger2自動生成的DaggerA2Component類(這裏只撿主要代碼粘貼):

public final class DaggerA2Component implements A2Component {
    private Provider<A2> povideAZhangSanProvider;
    private Provider<A2> povideALisiProvider;
    private Provider<A3> provideA3Provider;
    private Provider<A4> provideA4Provider;
    private MembersInjector<DaggerActivity> daggerActivityMembersInjector;

    private DaggerA2Component(DaggerA2Component.Builder builder) {
        assert builder != null;

        this.initialize(builder);
    }

    public static DaggerA2Component.Builder builder() {
        return new DaggerA2Component.Builder();
    }

    public static A2Component create() {
        return builder().build();
    }

    private void initialize(DaggerA2Component.Builder builder) {
        this.povideAZhangSanProvider = A2Module_PovideAZhangSanFactory.create(builder.a2Module);
        this.povideALisiProvider = A2Module_PovideALisiFactory.create(builder.a2Module);
        this.provideA3Provider = A2Module_ProvideA3Factory.create(builder.a2Module);
        this.provideA4Provider = ScopedProvider.create(A2Module_ProvideA4Factory.create(builder.a2Module));
        this.daggerActivityMembersInjector = DaggerActivity_MembersInjector.create(MembersInjectors.noOp(), this.povideAZhangSanProvider, this.povideALisiProvider, this.provideA3Provider, this.provideA4Provider);
    }

    public void inject(DaggerActivity mainActivity) {
        this.daggerActivityMembersInjector.injectMembers(mainActivity);
    }

   
}

能夠看到對於A2Module裏的四個被@Provides註解的方法,DaggerA2Component生成了四個Provider對象,

private Provider<A2> povideAZhangSanProvider;
    private Provider<A2> povideALisiProvider;
    private Provider<A3> provideA3Provider;
    private Provider<A4> provideA4Provider;

而這四個對象的建立時重點 ,在initialize()方法中,能夠發現前三個對象的建立都是xx_Factory.create()方式,而使用@PerActivity註解的provideA4Provider則是ScopedProvider.create()建立,區別就在這裏了,Factory工廠模式建立的對象每次都是新建的對象,而ScopedProvider則能夠返回上次建立的對象,起到了單例的做用。

具體可看ScopedProvider類

public final class ScopedProvider<T> implements Provider<T> {
  private static final Object UNINITIALIZED = new Object();

  private final Factory<T> factory;
  private volatile Object instance = UNINITIALIZED;

  private ScopedProvider(Factory<T> factory) {
    assert factory != null;
    this.factory = factory;
  }

  @SuppressWarnings("unchecked") // cast only happens when result comes from the factory
  @Override
  public T get() {
    // double-check idiom from EJ2: Item 71
    Object result = instance;
    if (result == UNINITIALIZED) {
      synchronized (this) {
        result = instance;
        if (result == UNINITIALIZED) {
          instance = result = factory.get();
        }
      }
    }
    return (T) result;
  }

  /** Returns a new scoped provider for the given factory. */
  public static <T> Provider<T> create(Factory<T> factory) {
    if (factory == null) {
      throw new NullPointerException();
    }
    return new ScopedProvider<T>(factory);
  }
}

能夠看到 T get()方法取A4對象時,使用了單例方法,若是已被建立則直接返回。

子Component

子Component跟前面的一個Component依賴另外一個Component有點像,區別是子Component能夠獲取到父Component的全部能夠生產出的對象,而Component依賴則只能獲取到被依賴的Component所暴露出來的能夠生產的對象。

A4 類:
public class A4 {

    @Inject
    public A4() {
    }

    private int age;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
@Component(dependencies = AComponent.class, modules = A2Module.class)
public interface A2Component {
    void inject(DaggerActivity mainActivity);

    A4Component plus(A4Module module1); // //參數爲A4Component依賴的Module
}
@Subcomponent(modules = A4Module.class)
public interface A4Component {
    void inject(DaggerActivity mainActivity);
}
DaggerActivity 
public class DaggerActivity extends Activity {

    private static final String TAG = "DaggerActivity";

    @Inject
    A2 aaa2;

    @Inject
    A4 aaa4;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        DaggerA2Component.builder()
                .a2Module(new A2Module())
                .build()
                .plus(new A4Module())
                .inject(this);


        aaa2.setAge(20);
        aaa2.getAge();
        Log.d(TAG, "onCreate --> aaa2.getAge() : : " + aaa2.getAge());

        aaa4.setAge(30);
        aaa4.getAge();
        Log.d(TAG, "onCreate --> aaa4.getAge() : : " + aaa4.getAge());

        Log.d(TAG, "onCreate ------------------------------------------>  : ");

    }
}

能夠看到  A4在這裏也能夠正常使用。

@Named註解


這個註解是用來設置別名的,用來區分同一個類型的不一樣對象。好比咱們都知道Android 中的Context有兩種,一種是全局的,一種是Activity中的,爲了區分他們,咱們就能夠加上別名;又好比有一個Person類,他有兩個實例,一個是張三,一個是李四,咱們也能夠用別名區分他們。

A2 類 :

public class A2 {

    public A2(int age) {
        this.age = age;
    }

    public A2() {
    }

    private int age;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

A2Module :

@Module
public class A2Module {

    @Named("李四")
    @Provides
    A2 povideA2() {
        return new A2(21);
    }

    @Named("張三")
    @Provides
    A2 povideA21() {
        return new A2(25);
    }

}

使用 :

public class DaggerActivity extends Activity {

    private static final String TAG = "DaggerActivity";

    @Named("張三")
    @Inject
    A2 aaa2;

    @Named("李四")
    @Inject
    A2 aaa2_lisi;



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
       
        DaggerA2Component.builder()
                .a2Module(new A2Module())
                .build()
                .inject(this);

        Log.d(TAG, "onCreate --> aaa2.getAge() : : " + aaa2.getAge());
        Log.d(TAG, "onCreate --> aaa2_lisi.getAge() : : " + aaa2_lisi.getAge());

    }
}

大致就寫到這裏了 。。。。

 

參考文檔 : 

http://www.2cto.com/kf/201604/499397.html

http://www.cnblogs.com/zhuyp1015/p/5119727.html

http://blog.csdn.net/duo2005duo/article/details/50696166

http://www.cnblogs.com/tiantianbyconan/archive/2016/01/02/5095426.html

相關文章
相關標籤/搜索