王學(xué)崗Dagger2的使用從簡單到復(fù)雜

第一部分

dagger2是一個(gè)依賴注入的框架,舉個(gè)例子如果我們不適用dagger注入窜护,我們調(diào)用一個(gè)對象必須使用構(gòu)造方法效斑,這樣就會造成了類與類的組合,但dagger的使用解決了這一問題柱徙。
這是dagger的官網(wǎng)

我們看一下跟dagger相關(guān)的概念缓屠,
@Inject
通常在需要依賴的地方使用這個(gè)注解奇昙。換句話說,你用它告訴Dagger這個(gè)類或者字段需要依賴注入敌完。這樣储耐,Dagger就會構(gòu)造一個(gè)這個(gè)類的實(shí)例并滿足他們的依賴。 官方點(diǎn)說就是帶有此注解的屬性或構(gòu)造方法將參與到依賴注入中蠢挡,Dagger2會實(shí)例化有此注解的類弧岳。
@Module
Modules類里面的方法專門用來提供依賴,他就像一個(gè)工廠一樣去生產(chǎn)需要添加依賴的實(shí)例业踏。所以我們定義一個(gè)類禽炬,用@Module來注解,這樣Dagger在構(gòu)造類的實(shí)例的時(shí)候勤家,就知道從哪里去找到需要的依賴腹尖。modules的一個(gè)重要特性是它們設(shè)計(jì)為分區(qū)并組合在一起(例如,我們的app中可以有多個(gè)組成在一起的modules)伐脖。它里面定義一些用@Provides注解的以provide開頭的方法热幔,這些方法就是所提供的依賴,Dagger2會在該類中尋找實(shí)例化某個(gè)類所需要的依賴讼庇。
@Provides
上面引入了這個(gè)概念了绎巨。在modules中,我們定義的方法是用@Provides這個(gè)注解蠕啄,以此來告訴Dagger我們想要構(gòu)造對象并提供這些依賴场勤。
@Component
Components從根本上來說他就是一個(gè)注入器,也可以說是用來將@Inject和@Module聯(lián)系起來的橋梁歼跟,它的主要作用就是連接這兩個(gè)部分和媳。Components可以提供所有定義了的類型的實(shí)例(inject需要),比如:我們必須用@Component注解一個(gè)接口然后列出所有的 哈街。功能是從@Module中獲取依賴并將依賴注入給@Inject

dagger必不可少的三個(gè)元素:Module,Component,Container
這里有張圖來說明它們之間的關(guān)系留瞳。


dagger2222222222.png

第二部分 Dagger2的基本使用(上)

下面我們看下具體怎么使用
首先要導(dǎo)入依賴

dependencies {
    implementation 'com.google.dagger:dagger:2.16'
    annotationProcessor 'com.google.dagger:dagger-compiler:2.16'}

這里有個(gè)ApiService的類,我們需要在MainActivity中使用它的實(shí)例骚秦,如果我們不用dagger她倘,我們就只能new ApiService(),但是我們現(xiàn)在使用dagger,就不需要new了作箍。

先看下ApiService這個(gè)沒用的類

package com.example.dagger2test;

import android.util.Log;
public class ApiService {
    public void register() {
        Log.i("zhang_xin","register成功");
    }
}

等下我們要使用dagger獲取它的實(shí)例帝牡。

package com.example.dagger2test;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import javax.inject.Inject;

public class MainActivity extends AppCompatActivity {
    @Inject     
    ApiService   mApiService;

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

在MainActivity里我們使用@inject注解,告訴dagger,我需要ApiService的實(shí)例蒙揣。dagger就會從@Component注釋的接口中尋找ApiService的實(shí)例,那好开瞭,我們下面創(chuàng)建這個(gè)接口懒震。

package com.example.dagger2test;

import dagger.Component;

@Component(modules = {罩息?.class})//關(guān)聯(lián)到module
public interface UserComponet {
 
}

大家看下Component的源碼

public @interface Component {
  /**
   * A list of classes annotated with {@link Module} whose bindings are used to generate the
   * component implementation. Note that through the use of {@link Module#includes} the full set of
   * modules used to implement the component may include more modules that just those listed here.
   */
  Class<?>[] modules() default {};

  /**
   * A list of types that are to be used as <a href="#component-dependencies">component
   * dependencies</a>.
   */
  Class<?>[] dependencies() default {};

可以發(fā)現(xiàn),Component需要module,我們需要在?處傳入我們的module
下面我們創(chuàng)建module

package com.example.dagger2test;

import dagger.Module;
import dagger.Provides;
 
public class UseModule {
    @Provides//提供依賴
    public ApiService provideApiService(){
        return new ApiService();
    }
}

在module里我們真正創(chuàng)建ApiService的實(shí)例个扰,這個(gè)提供ApiService實(shí)例的方法瓷炮,我們需要標(biāo)注為@provides
我們現(xiàn)在重新捋一下我們的思路
在MainActivity(就是圖中Container)中,我們需要ApiService的實(shí)例递宅,我們在ApiService上加上@inject注解娘香,這樣dagger就知道我們需要ApiService的實(shí)例,dagger就會去@Component注解下的類去找該實(shí)例办龄,commponent是一個(gè)橋梁烘绽,它關(guān)聯(lián)了很多modules。我們看下@Component的代碼

package com.example.dagger2test;

import dagger.Component;

@Component(modules = {UseModule.class}) 
public interface UserComponet {
    
}

注意俐填,以上只是Module與Component進(jìn)行了關(guān)聯(lián)安接,我說過Component是一個(gè)橋梁,所我們還需要把Component與MainActivity進(jìn)行關(guān)聯(lián)英融,

package com.example.dagger2test;

import dagger.Component;

@Component(modules = {UseModule.class})//關(guān)聯(lián)到module
public interface UserComponet {
    void inject(MainActivity activity);//關(guān)聯(lián)到Activity
}

從這行注釋@Component(modules = {UseModule.class}) ,dagger就知道要去UseModule里獲取ApiService的實(shí)例。
我們在看下UseModele類奏赘,在這個(gè)類里獲取ApiService的實(shí)例竹揍,注意,該類需要添加@module注解痕鳍。提供對象的方法添加@Prividers,方法的返回值為ApiService且有@Provides注釋硫豆,那么dagger就會從這個(gè)方法里獲取ApiService對象

package com.example.dagger2test;

import dagger.Module;
import dagger.Provides;
@Module
public class UseModule {
    @Provides//提供依賴
    public ApiService provideApiService(){
        return new ApiService();
    }
}

到這里我們在MainActivity(Container)里調(diào)用ApiService實(shí)例的代碼就全部完成了。然后我們r(jià)ebuild我們的工程
這個(gè)時(shí)候dagger會自動(dòng)生成DaggerUserComponet類额获,該類有個(gè)create(),會生成UserComponet的實(shí)例够庙,然后通過該實(shí)例我們調(diào)用UserComponet的inject方法。完整代碼如下

package com.example.dagger2test;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import javax.inject.Inject;

/**
 * 依賴注入框架抄邀,解決繁瑣的依賴關(guān)系
 * 必不可少的三種元素:Module,Component,Container,module提供依賴的集合耘眨,里面有很多方法是提供依賴的
 * ,component
 */
public class MainActivity extends AppCompatActivity {
    @Inject//dagger會從commponent里去找ApiService的實(shí)例境肾。使用依賴
    ApiService mApiService;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
//生成UserComponet的實(shí)例剔难,調(diào)用inject()
        DaggerUserComponet.create().inject(this);
        mApiService.register();
    }
}

運(yùn)行會輸出
10-20 15:22:10.585 22065-22065/com.example.dagger2test I/zhang_xin: register成功
為了方便大家看,我把所有相關(guān)的類在貼一遍奥喻。

package com.example.dagger2test;

import android.util.Log;
public class ApiService {
    public void register() {
        Log.i("zhang_xin","register成功");
    }
}

package com.example.dagger2test;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import javax.inject.Inject;

public class MainActivity extends AppCompatActivity {
    @Inject//dagger會從commponent里去找ApiService的實(shí)例偶宫。使用依賴
    ApiService mApiService;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DaggerUserComponet.create().inject(this);
        mApiService.register();
    }
}
package com.example.dagger2test;

import dagger.Component;

@Component(modules = {UseModule.class})//關(guān)聯(lián)到module
public interface UserComponet {
    void inject(MainActivity activity);//關(guān)聯(lián)到Activity
}

package com.example.dagger2test;

import dagger.Module;
import dagger.Provides;
@Module
public class UseModule {
    @Provides//提供依賴
    public ApiService provideApiService(){
        return new ApiService();
    }
}

第三部分 Dagger2的基本使用(下)

我們再來看一下復(fù)雜的例子。
我們需要MainActivity類里獲取UserManager實(shí)例环鲤,UserManager的構(gòu)造方法需要傳入另外兩個(gè)類的實(shí)例纯趋。我們看下UserManager類

package com.example.dagger2test;

public class UserManager {
    private ApiService apiService;
    private UserStore userStore;

    public UserManager(ApiService apiService, UserStore userStore) {
        this.apiService = apiService;
        this.userStore = userStore;
    }
    public void register(){
        apiService.register();
        userStore.register();
    }
}

這是UserStore類

package com.example.dagger2test;

import android.util.Log;

public class UserStore {
    public void register(){
        Log.i("zhang_xin","UserStore注冊成功");
    }
}

我們有兩種方法
第一種,修改UseModule文件

package com.example.dagger2test;

import dagger.Module;
import dagger.Provides;

@Module
public class UseModule {
    @Provides
    public ApiService getApiService() {
        return new ApiService();
    }

    @Provides
    public UserStore getUserStore() {
        return new UserStore();
    }

    @Provides
    public UserManager getUserManager(ApiService apiService, UserStore userStore) {
        return new UserManager(apiService, userStore);
    }
}

然后在MainActivity中調(diào)用用

package com.example.dagger2test;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import javax.inject.Inject;

public class MainActivity extends AppCompatActivity {
    @Inject
    UserManager userManager;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DaggerUserComponet.create().inject(this);
        userManager.register();
    }
}

看下打印輸出結(jié)果
10-20 17:03:03.092 27717-27717/com.example.dagger2test I/zhang_xin: ApiService register成功 UserStore注冊成功
第二種方法,使用構(gòu)造方法吵冒。
我們先把UseModule中方法注釋掉

package com.example.dagger2test;

import dagger.Module;
import dagger.Provides;

@Module
public class UseModule {
//    @Provides
//    public ApiService getApiService() {
//        return new ApiService();
//    }
//
//    @Provides
//    public UserStore getUserStore() {
//        return new UserStore();
//    }

    @Provides
    public UserManager getUserManager(ApiService apiService, UserStore userStore) {
        return new UserManager(apiService, userStore);
    }
}

然后修改ApiService和UseModule兩個(gè)類纯命,添加@Inject注釋的方法。

package com.example.dagger2test;

import android.util.Log;

import javax.inject.Inject;

public class UserStore {
    @Inject
    public UserStore(){

    }
    public void register(){
        Log.i("zhang_xin","UserStore注冊成功");
    }
}

package com.example.dagger2test;

import android.util.Log;

import javax.inject.Inject;

public class ApiService {
    @Inject
    public ApiService() {
    }

    public void register() {
        Log.i("zhang_xin", "ApiService register成功");
    }
}

運(yùn)行MainActivity
10-20 17:14:14.795 28228-28228/com.example.dagger2test I/zhang_xin: ApiService register成功 UserStore注冊成功
由以上兩種方法我們可以得出結(jié)論痹栖。
如果Module中沒有提供@Providers注釋的方法亿汞,Dagger會去調(diào)用@Inject注釋的方法。

第四部分

我們現(xiàn)在有這么個(gè)需求揪阿,那就是UseModule的構(gòu)造方法需要傳入?yún)?shù)疗我。我們修改下UseModule類

package com.example.dagger2test;

import android.content.Context;

import dagger.Module;
import dagger.Provides;

@Module
public class UseModule {
    private Context context;
    public UseModule (Context context){
        this.context=context;
    }
    @Provides
    public ApiService getApiService() {
        return new ApiService();
    }

    @Provides
    public UserStore getUserStore() {
        return new UserStore(this.context);
    }

    @Provides
    public UserManager getUserManager(ApiService apiService, UserStore userStore) {
        return new UserManager(apiService, userStore);
    }
}

現(xiàn)在大家看下,我們怎么在MainActivity類里調(diào)用
DaggerUserComponet.create().inject(this);肯定是行不通了

package com.example.dagger2test;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import javax.inject.Inject;

public class MainActivity extends AppCompatActivity {
    @Inject
    UserManager userManager;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DaggerUserComponet.builder().useModule(new UseModule(this)).build().inject(this);
        userManager.register();
    }
}

第五部分

假設(shè)我們現(xiàn)在有這么一個(gè)需求南捂,ApiService里需要傳入一個(gè)參數(shù)(實(shí)際開發(fā)中可能是OkHttpClient等吴裤,我們這里只簡單的使用Dog),我們可以這么做
黑毅,先看下Dog類

package com.example.dagger2test;

public class Dog {
}

看下UserManager類

package com.example.dagger2test;

public class UserManager {
    private ApiService apiService;
    private UserStore userStore;

    public UserManager(ApiService apiService, UserStore userStore) {
        this.apiService = apiService;
        this.userStore = userStore;
    }

    public void register(){
        apiService.register();
        userStore.register();
    }
}

看下ApiService類

package com.example.dagger2test;

import android.util.Log;

public class ApiService {
   private Dog dog;
//注意 dog是單例對象
    public ApiService(Dog dog) {
        this.dog = dog;
    }

    public void register() {
        Log.i("zhang_xin", "ApiService register成功");
    }
}

我們可以單獨(dú)寫一個(gè)針對Dog類的DogModule

package com.example.dagger2test;

import javax.inject.Singleton;

import dagger.Module;
import dagger.Provides;

@Module
public class DogModule {
    @Singleton//增加單例注釋
    @Provides
    public Dog getUser(){
        return new Dog();
    }
}

然后在UseModule中引用DogMoudle

package com.example.dagger2test;

import android.util.Log;

import javax.inject.Singleton;

import dagger.Module;
import dagger.Provides;
//includes引入另外一個(gè)module
@Module(includes = {DogModule.class})
public class UseModule {
    @Provides
    public ApiService getApiService(Dog dog) {
        Log.i("zhang_xin", "dog是否是單例:" + dog.toString());
        return new ApiService(dog);
    }

    @Provides
    public UserStore getUserStore() {
        return new UserStore();
    }

    @Provides
    public UserManager getUserManager(ApiService apiService, UserStore userStore) {
        return new UserManager(apiService, userStore);
    }
}

同時(shí)UserComponet也需要修改

package com.example.dagger2test;

import javax.inject.Singleton;

import dagger.Component;
//增加單例注釋
@Singleton
@Component(modules = {UseModule.class})//關(guān)聯(lián)到module
public interface UserComponet {
    void inject(MainActivity activity);//關(guān)聯(lián)到Activity
}

下面我們在MainActivity中調(diào)用

package com.example.dagger2test;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

import javax.inject.Inject;

public class MainActivity extends AppCompatActivity {
    @Inject
    UserManager userManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
      DaggerUserComponet.builder().useModule(new UseModule()).dogModule(new DogModule()).build().inject(this);
        userManager.register();
    }
}

最后我們看一下打印輸出
10-20 20:23:15.805 31622-31622/com.example.dagger2test I/zhang_xin: dog是否是單例:com.example.dagger2test.Dog@b45757d 10-20 20:23:15.809 31622-31622/com.example.dagger2test I/zhang_xin: ApiService register成功 UserStore注冊成功
多次打印都是這個(gè)值:com.example.dagger2test.Dog@b45757d嚼摩;
說明Dog確實(shí)是單例模式

除此之外還有一種方法,我們首先把UseModule恢復(fù)原來的樣子

package com.example.dagger2test;

import android.util.Log;

import javax.inject.Singleton;

import dagger.Module;
import dagger.Provides;
//這里刪除includes
@Module
public class UseModule {
    @Provides
    public ApiService getApiService(Dog dog) {
        Log.i("zhang_xin", "dog是否是單例:" + dog.toString());
        return new ApiService(dog);
    }

    @Provides
    public UserStore getUserStore() {
        return new UserStore();
    }

    @Provides
    public UserManager getUserManager(ApiService apiService, UserStore userStore) {
        return new UserManager(apiService, userStore);
    }
}

然后修改我們的UserComponet類

package com.example.dagger2test;

import javax.inject.Singleton;

import dagger.Component;
@Singleton
//增加DogModule.class
@Component(modules = {UseModule.class,DogModule.class})//關(guān)聯(lián)到module
public interface UserComponet {
    void inject(MainActivity activity);//關(guān)聯(lián)到Activity
}

其余的代碼不變矿瘦,效果一樣

第六部分 創(chuàng)建和區(qū)分不同實(shí)例(上)

我們現(xiàn)在有新的需求了枕面,我們在MainActivity里需要兩個(gè)ApiService對象,該怎么操作呢缚去?其實(shí)也很簡單潮秘,只需要在UseModule中提供兩個(gè)@Provides注釋的方法,同時(shí)在MainActivity和UseModule中添加@Named注釋易结,注意MainActivity中的@Named和UseModule中的@Named字段要一一對應(yīng)枕荞。看下代碼更一目了然
ApiService類

package com.example.dagger2test;

import android.util.Log;

public class ApiService {

    public void register() {
        Log.i("zhang_xin", "ApiService register成功");
        Log.i("zhang_xin",this.toString());
    }
}

MainActivity需要兩個(gè)ApiService類,每個(gè)對象前添加@Named注釋

package com.example.dagger2test;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

import javax.inject.Inject;
import javax.inject.Named;

public class MainActivity extends AppCompatActivity {
    @Named("1")
    @Inject
    ApiService apiService1;
    @Inject
    @Named("2")
    ApiService apiService2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DaggerUserComponet.builder().useModule(new UseModule()).build().inject(this);
        apiService1.register();
        apiService2.register();
    }
}

UseNodule類搞动,添加@Named注釋與MainActivity一一對應(yīng)

package com.example.dagger2test;

import javax.inject.Named;

import dagger.Module;
import dagger.Provides;

@Module
public class UseModule {
    @Provides
    @Named("1")
    public ApiService getApiService1(Dog dog) {
        return new ApiService();
    }
    @Provides
    @Named("2")
    public ApiService getApiService2(Dog dog) {
        return new ApiService();
    }
}

看下打印輸出
10-22 19:44:09.799 31505-31505/com.example.dagger2test I/zhang_xin: ApiService register成功 com.example.dagger2test.ApiService@b45757d 10-22 19:44:09.800 31505-31505/com.example.dagger2test I/zhang_xin: ApiService register成功 com.example.dagger2test.ApiService@20d4c72
可以看出兩個(gè)ApiService的內(nèi)存地址不一樣躏精,是兩個(gè)不同的對象。
注意鹦肿,如果我們不添加@Named注釋矗烛,dagger會根據(jù)返回值類型進(jìn)行匹配。

第七部分 dagger創(chuàng)建和區(qū)分不同實(shí)例(下)

上接第六部分箩溃,第六部分的功能我們還可以這樣實(shí)現(xiàn)瞭吃,自定義@Interface
我們首先自定義兩個(gè)@Interface文件,一個(gè)叫@First涣旨,一個(gè)叫@Second

package com.example.dagger2test;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;

import javax.inject.Qualifier;

import static java.lang.annotation.RetentionPolicy.RUNTIME;

@Qualifier
@Documented
@Retention(RUNTIME)
public @interface First {
}
package com.example.dagger2test;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;

import javax.inject.Qualifier;

import static java.lang.annotation.RetentionPolicy.RUNTIME;

@Qualifier
@Documented
@Retention(RUNTIME)
public @interface Second {
}

在UseModule和MainActivity中歪架,我們需要把@Named注釋分別改為@First和@Second,我們看下代碼

package com.example.dagger2test;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

import javax.inject.Inject;
import javax.inject.Named;

public class MainActivity extends AppCompatActivity {
    @First
    @Inject
    ApiService apiService1;
    @Second
    @Inject
    ApiService apiService2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DaggerUserComponet.builder().useModule(new UseModule()).build().inject(this);
        apiService1.register();
        apiService2.register();
    }
}

package com.example.dagger2test;

import dagger.Module;
import dagger.Provides;

@Module
public class UseModule {
    @Provides
    @First
    public ApiService getApiService1() {
        return new ApiService();
    }
    @Provides
    @Second
    public ApiService getApiService2() {
        return new ApiService();
    }
}

看下運(yùn)行效果
10-22 19:59:50.668 32434-32434/com.example.dagger2test I/zhang_xin: ApiService register成功 com.example.dagger2test.ApiService@b45757d ApiService register成功 10-22 19:59:50.669 32434-32434/com.example.dagger2test I/zhang_xin: com.example.dagger2test.ApiService@20d4c72

第八部分:Singleton 單例講解(上)

我們需要ApiService是單例模式
首先我們看下ApiService類

package com.example.dagger2test;

import android.util.Log;

public class ApiService {

    public void register() {
        Log.i("zhang_xin", "ApiService register成功");
        Log.i("zhang_xin",this.toString());
    }
}

這個(gè)時(shí)候我們需要在Module類的方法中添加@Singleton注釋霹陡,代碼如下

package com.example.dagger2test;

import javax.inject.Singleton;

import dagger.Module;
import dagger.Provides;

@Module
public class UseModule {
    @Singleton
    @Provides
    public ApiService getApiService() {
        return new ApiService();
    }
}

注意我們現(xiàn)在需要修改UserComponent類和蚪,他的類也需要添加@Singleton注釋

package com.example.dagger2test;

import javax.inject.Singleton;

import dagger.Component;
@Singleton//因?yàn)閁seModule添加了該注釋止状,所以這里也需要添加注釋
@Component(modules = {UseModule.class,DogModule.class})//關(guān)聯(lián)到module
public interface UserComponet {
    void inject(MainActivity activity);//關(guān)聯(lián)到Activity
}

然后我們看下MainActivity

 package com.example.dagger2test;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

import javax.inject.Inject;
import javax.inject.Named;

public class MainActivity extends AppCompatActivity {
    @Inject
    ApiService apiService1;
    @Inject
    ApiService apiService2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DaggerUserComponet.builder().useModule(new UseModule()).build().inject(this);
        apiService1.register();
        apiService2.register();

    }
}

我們多次運(yùn)行都會打印這個(gè)結(jié)果
10-22 20:33:15.896 3145-3145/com.example.dagger2test I/zhang_xin: ApiService register成功 com.example.dagger2test.ApiService@b45757d ApiService register成功 com.example.dagger2test.ApiService@b45757d
apiService1和apiService2內(nèi)存地址一樣,說明它們是同一個(gè)對象惠呼。

第八部分:Singleton 單例講解(下)

我們第七部分實(shí)現(xiàn)了單例模式导俘,但是這種方法實(shí)現(xiàn)的單例模式是有問題的,如果我們現(xiàn)在在創(chuàng)建一個(gè)MainActivity2和與之相關(guān)的@Component注釋的類剔蹋,那么這個(gè)時(shí)候我們無法保證兩個(gè)Activity中的ApiService是同一個(gè)。其實(shí)大家翻翻Dagger的源碼就會發(fā)現(xiàn)辅髓,Dagger的單例模式必須要保證是同一個(gè)@Component注釋的類泣崩。
我們先看這樣的一個(gè)例子,我們把訪問網(wǎng)絡(luò)的類CallNets設(shè)置為單例模式
這個(gè)是ApiService類洛口,他里面有一個(gè)CallNets類矫付,這個(gè)類是單例模式。

package com.example.daggertest2;

import android.util.Log;

public class ApiService {
    private CallNets callNets;

    public ApiService(CallNets callNets) {
        this.callNets = callNets;
    }

    public void register() {
        Log.i("zhang_xin", "apiService注冊成功");
    }
}

CallNets類第焰,實(shí)際開發(fā)中可能是OkhttpClient等买优。

package com.example.daggertest2;

public class CallNets {
//訪問網(wǎng)絡(luò)的邏輯
}

CallNetsModule類,方法我們注解成單例模式

package com.example.daggertest2;

import android.util.Log;

import javax.inject.Singleton;

import dagger.Module;
import dagger.Provides;

@Module
public class CallNetsModule {
    @Singleton
    @Provides
    public CallNets getCallNets(){
        CallNets callNets=new CallNets();
        Log.i("zhang_xin",callNets.toString());
        return callNets;
    }

}

接下來我們創(chuàng)建了兩個(gè)@Component注解的類

package com.example.daggertest2;

import javax.inject.Singleton;

import dagger.Component;
@Singleton
@Component(modules=UserModule.class)
public interface LoginComponet {
    void inject(LoginActivity activity);
}

package com.example.daggertest2;

import javax.inject.Singleton;

import dagger.Component;
@Singleton
@Component(modules = UserModule.class)
public interface UserComponet {
    void inject(MainActivity activity);
}

UserModule和UserManager

package com.example.daggertest2;

public class UserManager {
    private ApiService apiService;
    public UserManager(ApiService apiService){
        this.apiService=apiService;
    }
    public void register(){
        apiService.register();
    }
}

package com.example.daggertest2;

import dagger.Module;
import dagger.Provides;

@Module(includes = {CallNetsModule.class})
public class UserModule {

    @Provides
    public ApiService getApiService(CallNets callNets){
        return new ApiService(callNets);
    }
    @Provides
    public UserManager getUserManager(ApiService apiService){
        return new UserManager(apiService);
    }
}

兩個(gè)Activity

package com.example.daggertest2;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import javax.inject.Inject;

public class MainActivity extends AppCompatActivity {
    @Inject
    UserManager userManager;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DaggerUserComponet.builder().userModule(new UserModule()).callNetsModule(new CallNetsModule()).build().inject(this);
        userManager.register();
        startActivity(new Intent(this,LoginActivity.class));
    }
}

package com.example.daggertest2;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import javax.inject.Inject;

public class LoginActivity extends AppCompatActivity {
   @Inject
    UserManager userManager;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        DaggerLoginComponet.builder().userModule(new UserModule()).callNetsModule(new CallNetsModule()).build().inject(this);
        userManager.register();
    }
}

我們看下打印輸出
/zhang_xin: com.example.daggertest2.CallNets@b45757d /zhang_xin: apiService注冊成功 /zhang_xin: com.example.daggertest2.CallNets@eea8d0f /zhang_xin: apiService注冊成功
很明顯挺举,兩個(gè)CallNets不是同一個(gè)對象杀赢,我們雖然標(biāo)注了@Singleton,但因?yàn)閯?chuàng)建了兩個(gè)Componet,所以得到的是兩個(gè)不同的CallNets對象湘纵。
接下來我們就解決這個(gè)問題脂崔。
我們需要?jiǎng)?chuàng)建一個(gè)最高級別的Component
首先我們把CallNetsModule中無法提供單例的方法注釋掉

package com.example.daggertest2;

import android.util.Log;

import javax.inject.Singleton;

import dagger.Module;
import dagger.Provides;

@Module
public class CallNetsModule {
//    @Singleton
//    @Provides
//    public CallNets getCallNets(){
//        CallNets callNets=new CallNets();
//        Log.i("zhang_xin",callNets.toString());
//        return callNets;
//    }

}

然后我們創(chuàng)建AppComponet和AppModule

package com.example.daggertest2;

import javax.inject.Singleton;

import dagger.Component;
@Singleton
@Component(modules = AppModule.class)
public interface AppComponet {
    //這里不需要提供inject方法,因?yàn)槲覀儾恍枰⑷胛嗯纾且栏接谄渌腃onmponent
}

我們在AppModule類中提供CallNets的單例


import android.util.Log;

import javax.inject.Singleton;

import dagger.Module;
import dagger.Provides;

@Module
public class AppModule {
    @Singleton
    @Provides
    public CallNets getCallNets(){
        CallNets callNets=new CallNets();
        Log.i("zhang_xin",callNets.toString());
        return callNets;
    }
}

然后修改LoginComponent UserComponent

package com.example.daggertest2;

import javax.inject.Singleton;

import dagger.Component;

/**
 * 1,在這里我解釋下砌左,我們的UserModule并沒有提供CallNets實(shí)例,如果Dagger在UserModule中沒有發(fā)現(xiàn)CallNets實(shí)例
 * 他就會去依賴既AppComponet.class里面去找.
 * 2,這里不能有@Singleton注釋铺敌,因?yàn)镃omponent的dependencies與Component
 * 自身的scope不能相同
 */

@Component(modules=UserModule.class,dependencies = AppComponet.class)
public interface LoginComponet {
    void inject(LoginActivity activity);

}

package com.example.daggertest2;

import javax.inject.Singleton;

import dagger.Component;

/**
 * 2,這里不能有@Singleton注釋汇歹,因?yàn)镃omponent的dependencies與Component
 * 自身的scope不能相同
 */
@Component(modules = UserModule.class,dependencies = AppComponet.class)
public interface UserComponet {
    void inject(MainActivity activity);
}

這里我做下說明


dagger1.ng.png

注意第五點(diǎn),所以我們沒辦法給LoginComponent和AppComponent添加@Singleton注釋偿凭,既然沒辦法添加@Singleton注釋产弹,那么我們該怎么給LoginComponent和AppComponent添加注釋呢?因?yàn)镈agger給我們提供的注釋只有@Singleton笔喉,所以需要我們自己定義注釋取视。

package com.example.daggertest2;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;

import javax.inject.Scope;

import static java.lang.annotation.RetentionPolicy.RUNTIME;

@Scope
@Documented
@Retention(RUNTIME)
public @interface ActivityScope {
}

@scope注明是Scope
@documented標(biāo)記在文檔
@Retention 級別,有source class runtime

然后我們修改LoginComponent和UserComponent文件常挚,添加@ActivityScope 注釋作谭。

package com.example.daggertest2;

import javax.inject.Singleton;

import dagger.Component;

/**
 * 1,在這里我解釋下,我們的UserModule并沒有提供CallNets實(shí)例奄毡,如果Dagger在UserModule中沒有發(fā)現(xiàn)CallNets實(shí)例
 * 他就會去依賴既AppComponet.class里面去找.
 * 2,這里不能有@Singleton注釋折欠,因?yàn)镃omponent的dependencies與Component
 * 自身的scope不能相同
 */
@ActivityScope//添加該注釋
@Component(modules=UserModule.class,dependencies = AppComponet.class)
public interface LoginComponet {
    void inject(LoginActivity activity);

}

package com.example.daggertest2;

import dagger.Component;

/**
 * 2,這里不能有@Singleton注釋,因?yàn)镃omponent的dependencies與Component
 * 自身的scope不能相同
 */
@ActivityScope//添加該注釋
@Component(modules = UserModule.class,dependencies = AppComponet.class)
public interface UserComponet {
    void inject(MainActivity activity);
}

然后修改AppComponent類

package com.example.daggertest2;

import javax.inject.Singleton;

import dagger.Component;
@Singleton
@Component(modules = AppModule.class)
public interface AppComponet {
 Conmponent
    CallNets getCallNets();
}

在這里我們做一個(gè)橋接,這里的CallNets對象就是由AppModule提供的锐秦。
我們現(xiàn)在reBuild工程咪奖,已經(jīng)可以了沒有報(bào)錯(cuò)
可是我們現(xiàn)在又面臨一個(gè)問題,接下來我們該怎樣在LoginActivity和MainActivity中使用AppComponent呢酱床?
DaggerUserComponet.builder().userModule(new UserModule()).appComponet();
我們可以看到appComponent()需要傳入AppComponet類型的對象羊赵,在這里我們怎么給appComponent()傳入?yún)?shù)呢?
因?yàn)镾ingleton是application級別的扇谣,所以我們需要在Application中將AppComponent實(shí)例化昧捷。創(chuàng)建MyApplication繼承Application。

package com.example.daggertest2;

import android.app.Application;
import android.util.Log;

public class MyApplication extends Application {
    private AppComponet appComponet;
    @Override
    public void onCreate() {
        super.onCreate();
       appComponet= DaggerAppComponet.create();
    }

    public AppComponet getAppComponet() {
        return appComponet;
    }
}

然后我們就可以在MainActivity 和LoginActivity里調(diào)用了

package com.example.daggertest2;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

import javax.inject.Inject;

public class MainActivity extends AppCompatActivity {
    @Inject
    UserManager userManager;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DaggerUserComponet.builder().userModule(new UserModule())
                .appComponet(((MyApplication) getApplication())
                        .getAppComponet()).build().inject(this);
        userManager.register();
        startActivity(new Intent(this, LoginActivity.class));
    }
}

package com.example.daggertest2;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import javax.inject.Inject;

public class LoginActivity extends AppCompatActivity {
   @Inject
    UserManager userManager;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        DaggerLoginComponet.builder().userModule(new UserModule())
                .appComponet(((MyApplication) getApplication())
                        .getAppComponet()).build().inject(this);
         userManager.register();
    }
}

這樣我們就實(shí)現(xiàn)了單例模式
我們在ApiService中添加打印數(shù)據(jù)罐寨,測試下是不是單例模式

package com.example.daggertest2;

import android.util.Log;

public class ApiService {
    private CallNets callNets;

    public ApiService(CallNets callNets) {
        this.callNets = callNets;
    }

    public void register() {
        Log.i("zhang_xin", "apiService注冊成功"+this.callNets.toString());
    }
}

看下打印結(jié)果

10-24 16:22:59.691 2967-2967/com.example.daggertest2 I/zhang_xin: apiService注冊成功com.example.daggertest2.CallNets@4a7ac880
10-24 16:22:59.701 2967-2967/com.example.daggertest2 I/zhang_xin: apiService注冊成功com.example.daggertest2.CallNets@4a7ac880

OK靡挥,大功告成!

第九部分:一個(gè)Commponent關(guān)聯(lián)兩個(gè)Module

兩個(gè)Object類鸯绿,要通過注入獲取實(shí)例的類

package com.example.dagger2test;

/**
 * @author writing
 * @time 2019/10/25 21:29
 * @note
 */
public class DatabaseObject {
}

package com.example.dagger2test;

/**
 * @author writing
 * @time 2019/10/25 21:29
 * @note
 */
public class HttpObject {
}

兩個(gè)module類

package com.example.dagger2test;

import dagger.Module;
import dagger.Provides;

/**
 * @author writing
 * @time 2019/10/25 21:28
 * @note
 */
@Module
public class DatabaseModule {
    @Provides
    public DatabaseObject providerHttpObject(){
        return new DatabaseObject();
    }
}

package com.example.dagger2test;

import dagger.Module;
import dagger.Provides;

/**
 * @author writing
 * @time 2019/10/25 21:28
 * @note
 */
@Module
public class HttpModule {
    @Provides
    public HttpObject providerHttpObject(){
        return new HttpObject();
    }
}

component類

package com.example.dagger2test;

import dagger.Component;

/**
 * @author writing
 * @time 2019/10/25 21:33
 * @note
 */
@Component(modules = {HttpModule.class,DatabaseModule.class})
public interface MyComponent {
    void injectMainActivity(MainActivity mainActivity);
}

在MainActivity中的使用

package com.example.dagger2test;

import android.os.Bundle;
import android.util.Log;

import androidx.appcompat.app.AppCompatActivity;

import javax.inject.Inject;


public class MainActivity extends AppCompatActivity {
@Inject
HttpObject httpObject;
@Inject
DatabaseObject databaseObject;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
       DaggerMyComponent.create().injectMainActivity(this);
       Log.i("zhang_xin",httpObject.hashCode()+"");
       Log.i("zhang_xin",databaseObject.hashCode()+"");

    }
}

第十部份:全局單例的另一種方式

創(chuàng)建MyApplication,在application中注入
兩個(gè)通過注入獲取對象的類

package com.example.dagger2test;

/**
 * @author writing
 * @time 2019/10/25 21:29
 * @note
 */
public class DatabaseObject {
}

package com.example.dagger2test;

/**
 * @author writing
 * @time 2019/10/25 21:29
 * @note
 */
public class HttpObject {
}

對應(yīng)的module

package com.example.dagger2test;

import dagger.Module;
import dagger.Provides;

/**
 * @author writing
 * @time 2019/10/25 21:28
 * @note
 */
@Module
public class DatabaseModule {
    @Provides
    public DatabaseObject providerHttpObject(){
        return new DatabaseObject();
    }
}

package com.example.dagger2test;

import javax.inject.Singleton;

import dagger.Module;
import dagger.Provides;

/**
 * @author writing
 * @time 2019/10/25 21:28
 * @note
 */
@Singleton
@Module
public class HttpModule {
    @Singleton
    @Provides
    public HttpObject providerHttpObject(){
        return new HttpObject();
    }
}

component類

package com.example.dagger2test;

import javax.inject.Singleton;

import dagger.Component;

/**
 * @author writing
 * @time 2019/10/25 21:33
 * @note
 */
@Singleton
@Component(modules = {HttpModule.class,DatabaseModule.class})
public interface MyComponent {
    void injectMainActivity(MainActivity mainActivity);
    void injectSecondActivity(SecondActivity secondActivity);
}

Application

package com.example.dagger2test;

import android.app.Application;

/**
 * @author writing
 * @time 2019/10/25 21:51
 * @note
 */
public class MyApplication extends Application {
    private MyComponent myComponent;

    @Override
    public void onCreate() {
        super.onCreate();
        myComponent = DaggerMyComponent.builder().httpModule(new HttpModule()).build();
    }
    public MyComponent getAppComponent(){
        return myComponent;
    }
}

兩個(gè)Activity

package com.example.dagger2test;

import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;

import androidx.appcompat.app.AppCompatActivity;

import javax.inject.Inject;


public class MainActivity extends AppCompatActivity {
@Inject
HttpObject httpObject;
@Inject
HttpObject httpObject2;
@Inject
DatabaseObject databaseObject;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ((MyApplication)getApplication()).getAppComponent().injectMainActivity(this);
       Log.i("zhang_xin",httpObject.hashCode()+"");
       Log.i("zhang_xin",httpObject2.hashCode()+"");
       Log.i("zhang_xin",databaseObject.hashCode()+"");
       findViewById(R.id.textView).setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View view) {
               startActivity(new Intent(MainActivity.this,SecondActivity.class));
           }
       });
    }
}

package com.example.dagger2test;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.util.Log;

import javax.inject.Inject;

public class SecondActivity extends AppCompatActivity {
    @Inject
    HttpObject httpObject;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        ((MyApplication)getApplication()).getAppComponent().injectSecondActivity(this);
        Log.i("zhang_xin",httpObject.hashCode()+"");
    }
}

打印輸出結(jié)果

2019-10-25 22:36:18.469 27216-27216/com.example.dagger2test I/zhang_xin: 134041457
2019-10-25 22:36:18.469 27216-27216/com.example.dagger2test I/zhang_xin: 134041457
2019-10-25 22:36:18.469 27216-27216/com.example.dagger2test I/zhang_xin: 125137238
2019-10-25 22:36:27.658 27216-27216/com.example.dagger2test I/zhang_xin: 134041457

第十一部份:增加表示層對象PresenterModule PresenterComponent

我們現(xiàn)在增加了PresenterModule和PresenterComponent跋破,我同樣希望把它注入到MainActivity中。
我們在創(chuàng)建PresenterComponent

package com.example.dagger2test;

import dagger.Component;

/**
 * @author writing
 * @time 2019/10/26 12:35
 * @note
 */
@Component(modules = {PresenterModule.class})
public interface PresenterComponent {
    void injectMainActivity(MainActivity mainActivity);
}

但這個(gè)時(shí)候我們只要Rebuild就會報(bào)錯(cuò)瓶蝴,原因也很簡單毒返,我們要注入MainActivity,就會生成MainActivity_MembersInjector類囊蓝,但現(xiàn)在我們有兩個(gè)Compent都要生成MainActivity_MembersInjector類饿悬,就會產(chǎn)生沖突。
我們看下完整代碼聚霜,是怎么解決的
先創(chuàng)建PresenterModule和PresenterObject

package com.example.dagger2test;

/**
 * @author writing
 * @time 2019/10/26 12:33
 * @note
 */
public class PresenterObject {
}

package com.example.dagger2test;

import dagger.Module;
import dagger.Provides;

/**
 * @author writing
 * @time 2019/10/26 12:34
 * @note
 */
@Module
public class PresenterModule {
    @Provides
    public PresenterObject providePresenterObject(){
        return new PresenterObject();
    }
}

創(chuàng)建PresenterObjectComponent狡恬,不直接注入MainActivity中

package com.example.dagger2test;

import dagger.Component;

/**
 * @author writing
 * @time 2019/10/26 12:35
 * @note
 */
@Component(modules = {PresenterModule.class})
public interface PresenterObjectComponent {
//    void injectMainActivity(MainActivity mainActivity);
    //這樣組件就不在注入到MainActivity中了,只負(fù)責(zé)對象提供
     PresenterObject providerPresenterObject();
}

修改MyCmponent和MyApplication

package com.example.dagger2test;

import javax.inject.Singleton;

import dagger.Component;

/**
 * @author writing
 * @time 2019/10/25 21:33
 * @note
 */
@Singleton
@Component(modules = {HttpModule.class,DatabaseModule.class},dependencies = {PresenterObjectComponent.class})
public interface MyComponent {
    void injectMainActivity(MainActivity mainActivity);
    void injectSecondActivity(SecondActivity secondActivity);
}

package com.example.dagger2test;

import android.app.Application;

/**
 * @author writing
 * @time 2019/10/25 21:51
 * @note
 */
public class MyApplication extends Application {
    private MyComponent myComponent;

    @Override
    public void onCreate() {
        super.onCreate();
        myComponent = DaggerMyComponent.builder().httpModule(new HttpModule())
                //rebuild后增加presenterObjectComponent
                .presenterObjectComponent(DaggerPresenterObjectComponent.create()).build();
    }
    public MyComponent getAppComponent(){
        return myComponent;
    }
}

看下MainActivity代碼

package com.example.dagger2test;

import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;

import androidx.appcompat.app.AppCompatActivity;

import javax.inject.Inject;


public class MainActivity extends AppCompatActivity {
@Inject
HttpObject httpObject;
@Inject
HttpObject httpObject2;
@Inject
DatabaseObject databaseObject;
@Inject
PresenterObject presenterObject;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ((MyApplication)getApplication()).getAppComponent().injectMainActivity(this);
       Log.i("zhang_xin",httpObject.hashCode()+"");
       Log.i("zhang_xin",httpObject2.hashCode()+"");
       Log.i("zhang_xin",databaseObject.hashCode()+"");
       Log.i("zhang_xin",presenterObject.hashCode()+"");
       findViewById(R.id.textView).setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View view) {
               startActivity(new Intent(MainActivity.this,SecondActivity.class));
           }
       });
    }
}

打印輸出如下

2019-10-26 13:01:10.736 6681-6681/com.example.dagger2test I/zhang_xin: 33405208
2019-10-26 13:01:10.736 6681-6681/com.example.dagger2test I/zhang_xin: 33405208
2019-10-26 13:01:10.736 6681-6681/com.example.dagger2test I/zhang_xin: 134041457
2019-10-26 13:01:10.736 6681-6681/com.example.dagger2test I/zhang_xin: 125137238

其余代碼同第十部分

第十二部份:兩個(gè)單例的寫法

我們現(xiàn)在在PresentModule和PresentComponent添加@Singlenton會rebuild錯(cuò)誤
我們看下Singleton這個(gè)注釋源碼

/*
 * Copyright (C) 2009 The JSR-330 Expert Group
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package javax.inject;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
 * Identifies a type that the injector only instantiates once. Not inherited.
 *
 * @see javax.inject.Scope @Scope
 */
@Scope
@Documented
@Retention(RUNTIME)
public @interface Singleton {}

Scope(繪畫空間)是類似于作用域蝎宇,標(biāo)識只在某種地方(比如一個(gè)類弟劲,一個(gè)頁面,一個(gè)瀏覽器)有效.這個(gè)問題怎么解決呢姥芥?原因也很簡單兔乞,我們不使用@Single通這個(gè)坑貨,我們定義自己的@Singleton
創(chuàng)建自己的MySingleton

package com.example.dagger2test;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;

import javax.inject.Scope;

import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
 * @author writing
 * @time 2019/10/26 13:16
 * @note
 */
@Scope
@Documented
@Retention(RUNTIME)
public @interface MySingleton {
}

我們把第十部分凉唐,第十一部分中的@Singleton全部換成@MySingleton,運(yùn)行可以發(fā)現(xiàn)沒有任何問題
這里我就強(qiáng)調(diào)兩點(diǎn)
@Singleton只是一個(gè)模板庸追,我們需要scope都自定義
dependencies:組件依賴

  • 1.多個(gè)組件之間的scope不能相同
  • 2.沒有scope的不能依賴有scope的組件
package com.example.lsn37_dagger2.di;

import com.example.lsn37_dagger2.MainActivity;
import com.example.lsn37_dagger2.SecActivity;
import com.example.lsn37_dagger2.di.presenter_di.PresenterComponent;
import com.example.lsn37_dagger2.di.scope.AppScope;

import javax.inject.Singleton;

import dagger.Component;
import dagger.Subcomponent;

/**
* 這就是一個(gè)組件
* @Singleton只是一個(gè)模板,我們需要scope都自定義
* dependencies:組件依賴
* 1.多個(gè)組件之間的scope不能相同
* 2.沒有scope的不能依賴有scope的組件
*/
@AppScope
@Component(modules = {HttpModule.class,DatabaseModule.class}
           ,dependencies = {PresenterComponent.class})
public interface MyComponent {
   void injectMainActivity(MainActivity mainActivity);
   void injectSecActivity(SecActivity secActivity);
}

如果我們需要PresenterObject也單例該如何操作呢台囱?很好辦淡溯,在自定義一個(gè)單例

package com.example.dagger2test;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;

import javax.inject.Scope;

import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
 * @author writing
 * @time 2019/10/26 13:16
 * @note
 */
@Scope
@Documented
@Retention(RUNTIME)
public @interface MySingleton1 {
}

package com.example.dagger2test;

import javax.inject.Singleton;

import dagger.Module;
import dagger.Provides;

/**
 * @author writing
 * @time 2019/10/26 12:34
 * @note
 */
@MySingleton1
@Module
public class PresenterModule {
    @MySingleton1
    @Provides
    public PresenterObject providePresenterObject(){
        return new PresenterObject();
    }
}

package com.example.dagger2test;

import javax.inject.Singleton;

import dagger.Component;

/**
 * @author writing
 * @time 2019/10/26 12:35
 * @note
 */
@MySingleton1
@Component(modules = {PresenterModule.class})
public interface PresenterObjectComponent {
//    void injectMainActivity(MainActivity mainActivity);
    //這樣組件就不在注入到MainActivity中了,只負(fù)責(zé)對象提供
     PresenterObject providerPresenterObject();
}

其它的代碼不變簿训,可以發(fā)現(xiàn)presenterObject和HttpObject都是單例了

第十三部分咱娶,SubComponent的使用米间,組件與組件依賴的另一種方式

上面我們用組件依賴我們使用dependcies,現(xiàn)在我們換一種方式。
我們新創(chuàng)建一個(gè)項(xiàng)目
兩個(gè)Object膘侮,需要通過注入創(chuàng)建的對象

package com.example.dagger2test2;

/**
 * @author writing
 * @time 2019/10/26 14:21
 * @note
 */
public class DataBaseObject {
}

package com.example.dagger2test2;

/**
 * @author writing
 * @time 2019/10/26 14:21
 * @note
 */
public class HttpObject {
}

兩個(gè)module

package com.example.dagger2test2;

import dagger.Module;
import dagger.Provides;

/**
 * @author writing
 * @time 2019/10/26 14:26
 * @note
 */
@Module
public class DataBaseModule {
    @Provides
    public DataBaseObject providersDataBaseObject(){
        return new DataBaseObject();
    }
}

package com.example.dagger2test2;

import dagger.Module;
import dagger.Provides;

/**
 * @author writing
 * @time 2019/10/26 14:25
 * @note
 */
@Module
public class HttpObjectModule {
    @Provides
    public HttpObject providerHttpObject(){
        return new HttpObject();
    }
}

兩個(gè)Component

package com.example.dagger2test2;


import dagger.Subcomponent;

/**
 * @author writing
 * @time 2019/10/26 14:31
 * @note 這就是一個(gè)子組件
 */
@Subcomponent(modules = {DataBaseModule.class})
public interface DatabaseObjectComponent {
    void injectmMainActvity(MainActivity mainActivity);
}

package com.example.dagger2test2;

import dagger.Component;

/**
 * @author writing
 * @time 2019/10/26 14:29
 * @note
 */
@Component(modules = {HttpObjectModule.class})
public interface HttpObjectComponent {
//    void injectMainActivity(MainActivity mainActivity);
    DatabaseObjectComponent databaseObjectComponent();
}

MainActivity中調(diào)用

package com.example.dagger2test2;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.util.Log;

import javax.inject.Inject;

public class MainActivity extends AppCompatActivity {
@Inject
DataBaseObject dataBaseObject;
@Inject
HttpObject httpObject;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DaggerHttpObjectComponent.builder().httpObjectModule(new HttpObjectModule())
                .build()
                //我們自己HttpObjectComponent中定義的方法
                .databaseObjectComponent().injectmMainActvity(this);
        Log.i("zhang_xin",dataBaseObject.hashCode()+"");
        Log.i("zhang_xin",httpObject.hashCode()+"");
    }
}

打贏輸出

2019-10-26 15:28:28.194 15101-15101/com.example.dagger2test2 I/zhang_xin: 134041457
2019-10-26 15:28:28.195 15101-15101/com.example.dagger2test2 I/zhang_xin: 125137238

第十四部分:集合傳參

修改HttpObject

package com.example.dagger2test2;

/**
 * @author writing
 * @time 2019/10/26 14:21
 * @note
 */
public class HttpObject {
    public String baseUrl;
    public  HttpObject(String baseUrl){
        this.baseUrl = baseUrl;
    }
    public HttpObject(){}
}

修改HttpObjectModule

package com.example.dagger2test2;

import java.util.ArrayList;

import javax.inject.Named;

import dagger.Module;
import dagger.Provides;

/**
 * @author writing
 * @time 2019/10/26 14:25
 * @note
 */
@Module
public class HttpObjectModule {
    //參數(shù)可能不是一個(gè)屈糊,我們定義一個(gè)集合裝參數(shù)
    ArrayList<String> baseUrls;
    public HttpObjectModule(ArrayList<String> baseUrls){
        this.baseUrls = baseUrls;
    }
    @Named("baseurl1")
    @Provides
    public HttpObject providerHttpObject1(){
        return new HttpObject(baseUrls.get(0));
    }
    @Named("baseurl2")
    @Provides
    public HttpObject providerHttpObject2(){
        return new HttpObject(baseUrls.get(1));
    }
}

其它的不變
我們看下MainActivity中的調(diào)用

package com.example.dagger2test2;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.util.Log;

import java.util.ArrayList;

import javax.inject.Inject;
import javax.inject.Named;

public class MainActivity extends AppCompatActivity {

    @Inject
    DataBaseObject dataBaseObject;
    @Named("baseurl1")
    @Inject
    HttpObject httpObject1;
    @Named("baseurl2")
    @Inject
    HttpObject httpObject2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        String url1 = "www.baidu1.com";
        String url2 = "www.baidu2.com";
        ArrayList<String> urls = new ArrayList<>();
        urls.add(url1);
        urls.add(url2);
        DaggerHttpObjectComponent.builder().httpObjectModule(new HttpObjectModule(urls))
                .build()
                //我們自己HttpObjectComponent中定義的方法
                .databaseObjectComponent().injectmMainActvity(this);
        Log.i("zhang_xin", dataBaseObject.hashCode() + "");
        Log.i("zhang_xin", httpObject1.baseUrl + "");
        Log.i("zhang_xin", httpObject2.baseUrl + "");
    }
}

看下打印輸出的結(jié)果

2019-10-26 16:28:16.855 18917-18917/com.example.dagger2test2 I/zhang_xin: 33405208
2019-10-26 16:28:16.855 18917-18917/com.example.dagger2test2 I/zhang_xin: www.baidu1.com
2019-10-26 16:28:16.855 18917-18917/com.example.dagger2test2 I/zhang_xin: www.baidu2.com

第十五部分,解決Subcomponent傳參的問題

在第十三部分中琼了,我們有一個(gè)問題逻锐,那就是DataBaseObject這個(gè)類無法傳參,讀者可以自己試試雕薪,我這里就不演示了谦去。這是不是太坑了啊,我們在第十五部分就來解決這個(gè)問題蹦哼。解決辦法就是使用dependencies,這個(gè)在上面已經(jīng)有案例,就不講了要糊。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末纲熏,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子锄俄,更是在濱河造成了極大的恐慌局劲,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件奶赠,死亡現(xiàn)場離奇詭異鱼填,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)毅戈,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進(jìn)店門苹丸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人苇经,你說我怎么就攤上這事赘理。” “怎么了扇单?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵商模,是天一觀的道長。 經(jīng)常有香客問我蜘澜,道長施流,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任鄙信,我火速辦了婚禮瞪醋,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘扮碧。我一直安慰自己趟章,他們只是感情好杏糙,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蚓土,像睡著了一般宏侍。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蜀漆,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天谅河,我揣著相機(jī)與錄音,去河邊找鬼确丢。 笑死绷耍,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的鲜侥。 我是一名探鬼主播褂始,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼描函!你這毒婦竟也來了崎苗?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤舀寓,失蹤者是張志新(化名)和其女友劉穎胆数,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體互墓,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡必尼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了篡撵。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片判莉。...
    茶點(diǎn)故事閱讀 38,724評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖酸休,靈堂內(nèi)的尸體忽然破棺而出骂租,到底是詐尸還是另有隱情,我是刑警寧澤斑司,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布渗饮,位于F島的核電站,受9級特大地震影響宿刮,放射性物質(zhì)發(fā)生泄漏互站。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一僵缺、第九天 我趴在偏房一處隱蔽的房頂上張望胡桃。 院中可真熱鬧,春花似錦磕潮、人聲如沸翠胰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽之景。三九已至斤富,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間锻狗,已是汗流浹背满力。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留轻纪,地道東北人油额。 一個(gè)月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像刻帚,于是被迫代替她去往敵國和親潦嘶。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評論 2 350

推薦閱讀更多精彩內(nèi)容