Dagger2使用指北

Dagger2是正方形公司推出的一款依賴注入的框架,第二代由谷歌接手,在Android屆可是大名鼎鼎的難學(xué),我也是反復(fù)看了一遍又一遍才稍微有點(diǎn)頭緒,本文就是Dagger2的使用指北,包括后面如何集成到項(xiàng)目中,也盡量寫下來。

1.引入

    implementation 'com.google.dagger:dagger:2.16'
    annotationProcessor 'com.google.dagger:dagger-compiler:2.16'

2.Dagger2的作用是什么呢?

我們來看這樣一個例子,假如此時有一個Apple類,要在MainActivity中使用該類,傳統(tǒng)的方法,是在MainActivity類中new出這個對象,如下:

public class MainActivity extends AppCompatActivity {
    //使用
    Apple apple;
  
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
     
        apple = new Apple(20);
        Log.i("我是一個蘋果","");
    }
}

但是使用Dagger2,就不再需要new出Apple類,直接注入即可。如下:

public class MainActivity extends AppCompatActivity {
    //使用
    @Inject
    Apple apple;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //注入
        DaggerGangJingComponent.builder().appleModule(new AppleModule(90))
                .build().inject(this);
              Log.i("我是一個蘋果","");
    }
}

那么我們現(xiàn)在就是需要在項(xiàng)目中使用這個Apple類,怎么來使用Dagger2來創(chuàng)建呢?有哪些創(chuàng)建方式呢?后文會詳細(xì)解釋清楚。

1.最簡單不帶Module的inject方式

由我們自己定義的類,我們可以自由修改的前提下使用這種方式,分為兩種:帶參和不帶參。

構(gòu)造函數(shù)不帶參的類

  1. 由類提供:
//第一,將我們需要注入的對象的類的構(gòu)造參數(shù)使用@Inject標(biāo)注,告訴dagger2它可以實(shí)例化這個類;
public class Apple {
    @Inject
    public Apple() {
    }
}

2.由component連接

//第二,編寫Component接口使用@Component進(jìn)行標(biāo)注,里面的void inject()的參數(shù)表示要將依賴注入到的目標(biāo)位置;
@Component
public interface AppleComponent {
    void inject(MainActivity activity);
}

3.使用Apple

//
public class MainActivity extends AppCompatActivity {
    @Inject
    public Apple apple;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
//第三,使用android studio的Build菜單編譯一下項(xiàng)目,使它自動生成我們編寫的Component所對應(yīng)的類,生成的類的名字的格式為 "Dagger+我們所定義的Component的名字";

//第四,在需要注入的類中使用@Inject標(biāo)注要注入的變量;然后調(diào)用自動生成的Component類的方法create()或builder().build(),然后inject到當(dāng)前類;在這之后就可以使用這個@Inject標(biāo)注的變量了。
        DaggerAppleComponent.create().inject(this);

        Log.i("蘋果",apple+"");

    }
}

構(gòu)造函數(shù)帶參數(shù)的類,參數(shù)為引用類型
如果參數(shù)是基本類型呢?

  1. 假如Apple中帶有一個Kinfe類的參數(shù)如下:
public class Apple {
    
    Knife knife;
//Apple的構(gòu)造方法使用@Inject標(biāo)注,告訴Dagger2可以實(shí)例化這個類
    @Inject
    public Apple(Knife knife) {
      this.knife = knife;
    }
}

2.參數(shù)Knife的構(gòu)造方法也需要提供注入,由@Inject標(biāo)記,告訴Dagger2可以實(shí)例化這個類。

public class Knife {

    @Inject
    public Knife() {

    }
}

3.使用component連接二者:類和要注入該類的目標(biāo)位置。inject的參數(shù)就是要把該類注入到的目標(biāo)位置。

@Component
public interface AppleComponent {
    void inject(MainActivity activity);
}

4.Bulid一下項(xiàng)目,生成一個DaggerAppleComponent,通過該類使用注入的對象。

public class MainActivity extends AppCompatActivity {
    @Inject
    public Apple apple;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
//注入Apple
        DaggerAppleComponent.create().inject(this);
//使用Apple
        Log.i("蘋果",apple+","+apple.knife);

    }

2.帶Module的Inject方式

在不能更改構(gòu)造函數(shù)的情況下(比如引入第三方類OkHttpClient等),我們無法在構(gòu)造函數(shù)上添加@Inject標(biāo)記,就只能使用Module來實(shí)現(xiàn)類的提供。

構(gòu)造方法不帶參數(shù)

1.假如我們的Apple類是由第三方提供的,我們不可以更改其代碼。

public class Apple {
    Knife knife;
    public Apple() {
        
    }

    public Knife getKnife() {
        return knife;
    }

    public void setKnife(Knife knife) {
        this.knife = knife;
    }
}

2.編寫Module類,并且使用@Module標(biāo)注,在該類中提供我們需要inject的對象,提供該對象的方法使用@Provides標(biāo)注

@Module
public class AppleModule {

    @Provides
    public Apple providesApple(){
        return new Apple();
    }
}

3.在component接口中,使用modules = xxxModule.class鏈接上一步編寫的Module類。

@Component(modules = AppleModule.class)
public interface AppleComponent {
    void inject(MainActivity activity);
}

4.依然是在目標(biāo)位置注入該對象,并使用

public class MainActivity extends AppCompatActivity {
    @Inject
    public Apple apple;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DaggerAppleComponent.create().inject(this);
        Log.i("蘋果",apple+"");
    }
}

構(gòu)造函數(shù)帶參數(shù)

1.編寫Module類,使用@Module標(biāo)記,并且在Module的構(gòu)造方法中傳入?yún)?shù),參數(shù)和對象一樣,都需要寫個方法提供出來。

@Module
public class AppleModule {

    String name;

    public AppleModule(String name) {
        this.name = name;
    }

    @Provides
    public Apple providesApple(){
        return new Apple(name);
    }

    @Provides
    public String providesName(){
        return name;
    }
}

2.component接口寫法同上

@Component(modules = AppleModule.class)
public interface AppleComponent {
    void inject(MainActivity activity);
}

3.build一下,生成DaggerXXXModule類,使用該類的build方法并傳入?yún)?shù)來注入對象。

public class MainActivity extends AppCompatActivity {
    @Inject
    public Apple apple;

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

        DaggerAppleComponent.builder().appleModule(new AppleModule("藍(lán)色的蘋果"))
                .build().inject(this);

        Log.i("蘋果",apple+"");
    }
}

@Qualifier 自定義注解

現(xiàn)在有這樣的情況,如果一個類,有兩個構(gòu)造方法,一個帶參,一個不帶參,如果要同時使用帶參和不帶參的對象,那么怎么來區(qū)分呢?

1. 使用@Named注解進(jìn)行標(biāo)記。

使用該類型注解(@Named或者@Qualifier),不能直接在構(gòu)造函數(shù)上標(biāo)記,否則會報(bào)錯誤:

@Qualifier annotations are not allowed on @Inject constructors.

在Module類中,使用@Named注解標(biāo)記:

@Module
public class AppleModule {

    String name;

    public AppleModule(String name) {
        this.name = name;
    }

    @Provides
    @Named("normal")
    public Apple providesApple(){
        return new Apple();
    }
    @Provides
    @Named("named")
    public Apple providesNamedApple(){
        return new Apple(name);
    }

    @Provides
    public String providesName(){
        return name;
    }
}

2.使用時需要使用@Named進(jìn)行區(qū)分。

public class MainActivity extends AppCompatActivity {
    @Inject
    @Named("normal")
    public Apple apple;
    @Inject
    @Named("named")
    public Apple apple1;

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

        DaggerAppleComponent.builder().appleModule(new AppleModule("紅色")).build()
                .inject(this);
        Log.i("蘋果",apple+"");
        Log.i("蘋果1",apple1+""+apple1.name);
    }
}

3.其它創(chuàng)建Component接口的代碼均相同。

2.使用@Qualifier自定義注解

1.創(chuàng)建一個注解類 命名為Type,并用@Qualifier注解標(biāo)記,需要指明是運(yùn)行時注解。

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface Type {
    String value() default "";
}

2.把上一步中的Named全部換成自己定義的Type即可。
在Module中:

@Module
public class AppleModule {

    String name;

    public AppleModule(String name) {
        this.name = name;
    }

    @Provides
    @Type("normal")
    public Apple providesApple(){
        return new Apple();
    }
    @Provides
    @Type("named")
    public Apple providesNamedApple(){
        return new Apple(name);
    }

    @Provides
    public String providesName(){
        return name;
    }
}

使用時:

public class MainActivity extends AppCompatActivity {
   @Inject
   @Type("normal")
   public Apple apple;
   @Inject
   @Type("named")
   public Apple apple1;

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

       DaggerAppleComponent.builder().appleModule(new AppleModule("紅色")).build()
               .inject(this);
       Log.i("蘋果",apple+"");
       Log.i("蘋果1",apple1+""+apple1.name);
   }
}

Singleton 單例

怎樣使用Dagger2創(chuàng)建單例對象呢?

無Module方式

1.在對象類上使用@Singleton標(biāo)記

@Singleton
public class Apple {
    @Inject
    public Apple() {

    }
}

2.使用@Singleton標(biāo)記component接口

@Singleton
@Component
public interface AppleComponent {
    void inject(MainActivity activity);
}

3.注入并使用Apple對象

public class MainActivity extends AppCompatActivity {
    @Inject
    public Apple apple;
    @Inject
    public Apple apple1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DaggerAppleComponent.create().inject(this);
        Log.i("蘋果",apple+"");
        Log.i("蘋果1",apple1+"");
    }
}

打印結(jié)果如下:


image.png

有Module方式

出現(xiàn)Module類的初衷是對象類不可更改,因此,有Module類時,不需要對對象類進(jìn)行任何的更改,使用單例也只需要在Module類中進(jìn)行更改即可。
1.Module類中提供對象的方法上,使用@Singleton標(biāo)記。

@Module
public class AppleModule {

    String name;

    public AppleModule(String name) {
        this.name = name;
    }
    @Singleton
    @Provides
    public Apple providesApple(){
        return new Apple();
    }

    @Provides
    public String providesName(){
        return name;
    }
}

2.其他代碼相同:包括使用@Singleton標(biāo)記component接口,注入并使用對象。

@Scope 作用域

在作用域內(nèi)單例。比如有三個Activity,只在前兩個Activity中實(shí)現(xiàn)單例。
1.創(chuàng)建自定義注解,使用@Scope注解標(biāo)記,并標(biāo)明是運(yùn)行時注解。

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

}

2.Module 和 component都是用自定義的@PerActivity進(jìn)行標(biāo)記。

Module:
@Module
public class AppleModule {
    @Provides
    @PerActivity
    public Apple providesApple(){
        return new Apple();
    }
}

Component:
@PerActivity
@Component(modules = AppleModule.class)
public interface AppleComponent {
    void inject(MainActivity activity);
    void inject(Main2Activity activity);
}

3.光使用注解劃定作用域還是不夠的,還需要創(chuàng)建一個Application,在其中獲取獲取AppleComponent對象。

public class AppleApplication extends Application {
   
    private AppleComponent appleComponent;
    @Override
    public void onCreate() {
        super.onCreate();
        // 獲取AppleComponent對象
        appleComponent = DaggerAppleComponent.builder().appleModule(new AppleModule())
                .build();
    }
    //提供外界獲取AppleComponent的方法
    public AppleComponent getAppleComponent() {
        return appleComponent;
    }
}

4.在需要使用單例Apple的位置獲取AppleComponent對象,并且注入
MainActivity.java

public class MainActivity extends AppCompatActivity {

    @Inject
    public Apple apple;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        ((AppleApplication)getApplication()).getAppleComponent().inject(this);

        Log.i("Main 蘋果", "onCreate: "+apple);

        findViewById(R.id.bn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                startActivity(new Intent(MainActivity.this,Main2Activity.class));
            }
        });
    }
}

Main2Activity.java

public class Main2Activity extends AppCompatActivity {
    
    @Inject
    public Apple apple;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);

        ((AppleApplication)getApplication()).getAppleComponent().inject(this);
        Log.i("Main2 蘋果",apple+"");

        findViewById(R.id.bn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                startActivity(new Intent(Main2Activity.this,Main3Activity.class));
            }
        });
    }
}

打印出的結(jié)果如下:

Main 蘋果: onCreate: com.kimliu.daggerdemo3.Apple@5ef1d24
Main2 蘋果: com.kimliu.daggerdemo3.Apple@5ef1d24

可以看到,兩個對象的地址相同。
5.不使用單例的目標(biāo)位置(Main3Activity),需要使用Apple,重新編寫Module,Component注入使用即可。

Module:
@Module
public class Main3Module {

    @Provides
    public Apple providesApple(){
        return new Apple();
    }
}

Component:
@Component(modules = Main3Module.class)
public interface Main3Component {
    void inject(Main3Activity activity);
}

//使用:

public class Main3Activity extends AppCompatActivity {
    
    @Inject
    public Apple apple;

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

        DaggerMain3Component.create().inject(this);

        Log.i("Main3Activity 蘋果", "onCreate: "+apple);

    }
}

本文參考:http://www.itdecent.cn/p/22c397354997/
http://www.itdecent.cn/p/ea4b89352e9a 感謝??

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容