Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 關於android開發 >> 安卓開發 第一篇 關於依賴注入框架dagger2的使用和理解

安卓開發 第一篇 關於依賴注入框架dagger2的使用和理解

編輯:關於android開發

安卓開發 第一篇 關於依賴注入框架dagger2的使用和理解


(這篇博客真是磨難重重啊,寫到一半電腦藍屏了,還好markdown編輯器保持了部分類容)

最近開始重構項目,在重構項目中用到了依賴注入框架dagger2,發現它確實很方便,能大大加快我們編寫代碼的速度,同時也很方便我們對於功能模塊的解耦。在這裡就不過多介紹dagger2了,大家谷歌 百度一下就能得到很多關於dagger2的介紹。學習dagger2是需要一定的學習成本的,我自己開始學習的時候也差不多花了一周的時間才弄明白怎樣使用dagger2,下面就說說自己對dagger2的理解和使用方法。

dagger2中最重要的就是module和component了,module是生產我們需要的對象的地方,component是聯系module和module生產出的對象的使用場景的橋梁。(說白了,dagger2就像是設計模式中的工廠模式,為我們生產各種我們需要的對象)

不明白?上代碼:(假如我們有一個類A,然後我們通過依賴注入方法要在MainActivity中使用)

×××××××××××××××××××××××不使用dagger2××××××××××××××××××××××××
//類A
public class A {
    private  int field;
      ...       //其他屬性

    public A() {
    }

    public void doSomething(){
        Log.i("美女","我愛你");
    }

    public void doOtherthing(){
        Log.i("美女","我是真的愛你");
    }
    ...    //其他方法
}
//類MainActivity
public class MainActivity extends AppCompatActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        A a=new A();
        a.doSomething();
        a.doOtherthing();
    }
}

×××××××××××××××××××××××使用dagger2××××××××××××××××××××××××
//類A
 public class A {
    private  int field;
      ...       //其他屬性

    public A() {
    }

    public void doSomething(){
        Log.i("美女","我愛你");
    }

    public void doOtherthing(){
        Log.i("美女","我是真的愛你");
    }
    ...    //其他方法
}
//我們先要構造一個Module,這個Module中生產A的對象
@Module
public class AMedule {

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

}

//然後需要一個Component,用了連接Module和MainActivity
@Component(modules = AMedule.class)
public interface ActivityComponent {
   A a();
}

//在MainActivity類中使用
public class MainActivity extends AppCompatActivity {

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

        ActivityComponent component=DaggerActivityComponent.builder()
                .aMedule(new AMedule())
                .build();

        A a=component.a();
        a.doSomething();
        a.doOtherthing();
    }
}

一個簡單的依賴注入就完成了。也許大家會覺得這樣寫很麻煩,其實不然,還有一種更加簡單的方法來做這件事,我們把B注入到BComponent中,直接使用@Inject注解:

//類A
 public class A {
    private  int field;
      ...       //其他屬性

    public A() {
    }

    public void doSomething(){
        Log.i("美女","我愛你");
    }

    public void doOtherthing(){
        Log.i("美女","我是真的愛你");
    }
    ...    //其他方法
}
//我們先要構造一個Module
@Module
public class AMedule {

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

}
//然後需要一個Component
@Component(modules = AMedule.class)
public interface ActivityComponent {
    void inject(MainActivity mainActivity);
}

//在MainActivity類中使用
public class MainActivity extends AppCompatActivity {
    @Inject
    A a;

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

       DaggerActivityComponent.builder()
                .aMedule(new AMedule())
                .build()
                .inject(this);


        a.doSomething();
        a.doOtherthing();
    }
}

怎麼樣,是不是簡單,方便一些了。什麼?還麻煩,那我們更進一步吧(由於這裡的A類是我們自己定義的,可以更進一步):

//類A
 public class A {
    private  int field;
      ...       //其他屬性

    @Inject
    public A() {
    }

    public void doSomething(){
        Log.i("美女","我愛你");
    }

    public void doOtherthing(){
        Log.i("美女","我是真的愛你");
    }
    ...    //其他方法
}
//我們先要構造一個Module(其實這裡Module已經用不到了,我們不需要通過Modu生產A了,不過為了與上面對比,還是留著吧)
@Module
public class AMedule {

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

}
//然後需要一個Component
@Component(modules = AMedule.class)
public interface ActivityComponent {
    void inject(MainActivity mainActivity);
}

//在MainActivity類中使用
public class MainActivity extends AppCompatActivity {
    @Inject
    A a;

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

       DaggerActivityComponent.builder()
                .aMedule(new AMedule())
                .build()
                .inject(this);

        a.doSomething();
        a.doOtherthing();
    }
}

是不是看迷糊了,A沒有在Module生產,那是怎麼來的呢?不知道大家注意到沒有,A的構造方法上面有個@Inject注解,沒錯,就是他,就是這個注解生產A對象的。

看到這裡,我們就知道dagger2生產對象有兩種方式,一種是在Module中通過@Provides注解加上providexxx 方法,另一種就是直接在要生產的對象的類的構造方法加上@inject注解。

那麼什麼時候用Module,什麼時候用@Inject呢?

在這裡悄悄告訴大家: 一般生成系統或者SDK或者第三方庫提供的類的對象時用Module,而自定義的類的對象用@Inject,當然,你也可以用一個類繼承系統或者SDK或者第三方庫提供的類,然後在其構造方法加上@Inject注解。
2. 可能大家對Module和Component的還是似懂非懂,在這裡在打一個形象一點的比喻吧。

例如到吃飯的時間了,我們要去做飯(吃外賣的繞道),我們得去廚房吧(希望不是野外燒烤),我們需要煤氣灶(也可能是電磁爐),鍋,刀,砧板,盆子….(發現需要的真多哈),這些都是一個個類吧,你廚房裡的那些具體的比如美的電飯煲(美的是不是得給點廣告費),蘇泊爾不粘鍋(剛買了一個)…..就是一個個具體的對象,我們有了這些具體的對象才能愉快的做飯,而Module就是讓我們得到這一個個對象(一個大工廠,生產美的電飯煲,蘇泊爾不粘鍋….),Component 就是我們的廚房,DaggerActivityComponent .builder().aMedule(new AMedule()).build() 就是讓我們擁有了一個廚房(想想機器貓的口袋,我們可以從裡面得到任何東西 ),我們可以從廚房裡面拿炊具做飯(往外拿:A a=component.a(),這是把廚房裡的東西拿到廚房外面,在外面做飯),而 DaggerActivityComponent.builder() .aMedule(new AMedule()) .build().inject(this)就是我們自己進入廚房,在廚房裡面 做飯(我們當然很容易獲得廚房裡面的炊具了,用@Inject獲得),好了,開始做飯。。。
3. 一個Component可以依賴多個Module,如
@Component(modules = {AModule.class,BModule.class,...})

同樣,Component也可以依賴另一個Component,如

@Component(dependencies = BComponent.class,modules = {AModule.class,BModule.class,...})

甚至多個Component,如

@Component(dependencies = {BComponent.class,CComponent.class,...}
,modules = {AModule.class,BModule.class,...})

有個需要注意的地方是被依賴的Component需要將對象暴露出來,依賴的Component才能夠獲取到這個對象,如
//被依賴Component
    @Component(modules = {...})
    public interface BComponent {
        A a();
        B b();
    }
//依賴Component
    @Component(dependencies = BComponent.class,modules = {...})
    public interface CComponent {

    }

CComponent可以通過BComponent獲取A,B的對象,其他BComponent的對象對CComponent來說是透明的,不可見。
4. @Scope注解

這個注解是用來劃分作用域的(在哪兒使用),意思就是說我劃出一塊區域來,生產出的東西如果限定到此作用域都放到這裡,作用域的場景類(一般就是消費對象的地方,比如Activity)下次需要某個對象的時候,我就來這兒拿,如果有,就直接拿來用,如果沒有,就生產,並且放到這裡,同時自己用(有沒有一種方便自己,方便他人的感覺),dagger2自已有個@Scope注解,叫@Singleton,就是大家都熟悉的單例模式,你也可以自定義@Scope注解,比如限定生產出的某個對象只能在Activity中使用,只能在Application中使用,只能在Fragment中使用等等。。。
例如:我們寫一個限定作用域為Activity的Scope注解

@Scope
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface PerActivity {

}

使用(構造函數方式)
//類A
@PerActivity
 public class A {
    private  int field;
      ...       //其他屬性

    @Inject
    public A() {
    }

    public void doSomething(){
        Log.i("美女","我愛你");
    }

    public void doOtherthing(){
        Log.i("美女","我是真的愛你");
    }
    ...    //其他方法
}

//然後需要一個Component
@PerActivity
@Component()
public interface ActivityComponent {
    void inject(MainActivity mainActivity);
}

//在MainActivity類中使用
public class MainActivity extends AppCompatActivity {
    @Inject
    A a;

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

       DaggerActivityComponent.builder()
                .build()
                .inject(this);

        a.doSomething();
        a.doOtherthing();
    }
}
使用(Module方式)
//類A
 public class A {
    private  int field;
      ...       //其他屬性

    public A() {
    }

    public void doSomething(){
        Log.i("美女","我愛你");
    }

    public void doOtherthing(){
        Log.i("美女","我是真的愛你");
    }
    ...    //其他方法
}
//我們先要構造一個Module
@Module
public class AMedule {

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

}
//然後需要一個Component
@PerActivity
@Component(modules = AMedule.class)
public interface ActivityComponent {
    void inject(MainActivity mainActivity);
}

//在MainActivity類中使用
public class MainActivity extends AppCompatActivity {
    @Inject
    A a;

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

       DaggerActivityComponent.builder()
                .aMedule(new AMedule())
                .build()
                .inject(this);

        a.doSomething();
        a.doOtherthing();
    }
}
沒看明白?好吧,我們繼續

假如我們還有一個SecondActivity也要使用A的對象

//類A
 public class A {
    private  int field;
      ...       //其他屬性

    public A() {
    }

    public void doSomething(){
        Log.i("美女","我愛你");
    }

    public void doOtherthing(){
        Log.i("美女","我是真的愛你");
    }
    ...    //其他方法
}
//我們先要構造一個Module
@Module
public class AMedule {

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

}
//然後需要一個Component
@PerActivity
@Component(modules = AMedule.class)
public interface ActivityComponent {
    void inject(MainActivity mainActivity);
    void inject(SecondActivity secondActivity);
}

//在MainActivity類中使用
public class MainActivity extends AppCompatActivity {
    @Inject
    A a;

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

       DaggerActivityComponent.builder()
                .aMedule(new AMedule())
                .build()
                .inject(this);

        a.doSomething();
        a.doOtherthing();
    }
}

//在SecondActivity類中使用
public class SecondActivity extends AppCompatActivity {
    @Inject
    A a;

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

       DaggerActivityComponent.builder()
                .aMedule(new AMedule())
                .build()
                .inject(this);

        a.doSomething();
        a.doOtherthing();
    }
}

那麼,這裡MainActivity和SecondActivity中的A的對象a是同一個
5. 子Component

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

例子:
//類A
 public class A {
    private  int field;
      ...       //其他屬性

    public A() {
    }

    public void doSomething(){
        Log.i("美女","我愛你");
    }

    public void doOtherthing(){
        Log.i("美女","我是真的愛你");
    }
    ...    //其他方法
}
//我們先要構造一個Module
@Module
public class AMedule {

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

}
//然後需要一個Component
@Component(modules = AMedule.class)
public interface ActivityComponent {
    void inject(MainActivity mainActivity);
void inject(SecondActivity secondActivity);
}

//然後需要一個Component
@Component(modules = AMedule.class)
public interface BComponent {
    void inject(MainActivity mainActivity);

    CComponent plus(Module1 module1,Module2 module2,...);//參數為CComponent依賴的Module

}

//然後一個子Component(使用@Subcomponent注解)
@Subcomponent(modules = {...})
public interface CComponent {

void inject(SecondActivity secondActivity);
}

//在MainActivity類中使用,將MainActivity注入到父Component中
public class MainActivity extends AppCompatActivity {
    @Inject
    A a;

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

       DaggerActivityComponent.builder()
                .aMedule(new AMedule())
                .build()
                .inject(this);

        a.doSomething();
        a.doOtherthing();
    }
}

//在SecondActivity類中使用,將SecondActivity注入到子Component中
public class SecondActivity extends AppCompatActivity {
    @Inject
    A a;

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

       DaggerActivityComponent.builder()
                .aMedule(new AMedule())
                .build()
        .plus(new Module1(),new Module2(),...)
                .inject(this);

        a.doSomething();
        a.doOtherthing();
    }
}

6.@Named注解
這個注解是用來設置別名的,用來區分同一個類型的不同對象。比如我們都知道Android 中的Context有兩種,一種是全局的,一種是Activity中的,為了區分他們,我們就可以加上別名;又比如有一個Person類,他有兩個實例,一個是小李,一個是小美,我們也可以用別名區分他們。

//Person類
public class Person {
    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

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

   @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

//我們先要構造一個Module
@Module
public class ActivityMedule {
   @Named("小李")
   @Provides
    Person  providePerson(){
        return  new Person("小李",18);
    }
   @Named("小美")
   @Provides
    Person  providePerson(){
        return  new Person("小美",24);
    }

}
//然後需要一個Component
@Component(modules = ActivityMedule.class)
public interface ActivityComponent {
    void inject(MainActivity mainActivity);
}
//在MainActivity類中使用
public class MainActivity extends AppCompatActivity {
    @Named("小李")
    @Inject
    Person p1;

    @Named("小美")
    @Inject
    Person p2;

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

       DaggerActivityComponent.builder()
                .activityMedule(new ActivityMedule())
                .build()
                .inject(this);

        Log.i("person",p1.toString());
        Log.i("person",p2.toString());
    }
}

當然,如果你覺得@Named注解滿足不了你的需求,你也可以使用@Qualifier來自定義自己的別名注解

7.在android studio的使用

在build.gradle中添加依賴庫

compile 'com.google.dagger:dagger:2.2' 
compile 'com.google.dagger:dagger-compiler:2.2' 
provided 'org.glassfish:javax.annotation:10.0-b28'

好了,大概就講這麼多吧!

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved