Dagger2學(xué)習(xí)筆記4(@Singleton 與@ Scope 實(shí)現(xiàn)全局單例與作用域單例)

Dagger2學(xué)習(xí)筆記1(基礎(chǔ)概念學(xué)習(xí))
Dagger2學(xué)習(xí)筆記2(學(xué)習(xí)Dagger2的簡(jiǎn)單使用)
Dagger2學(xué)習(xí)筆記3(各個(gè)注解學(xué)習(xí))

上篇文章中學(xué)習(xí)了Dagger2中各個(gè)注解的作用及如何使用, 其中涉及到兩個(gè)特殊的注解, @Singleton 和@ Scope, 接下來(lái)我們將學(xué)習(xí)怎么使用它們做到全局單例.
上篇文章我們學(xué)習(xí)到Singleton是繼承自Scope, 所以可以看做是Scope的代表實(shí)現(xiàn). Scope的作用是保證依賴對(duì)象在作用范圍內(nèi)單例, 提供局部范圍的單例,所謂局部范圍就是它的生命周期范圍
舉個(gè)栗子:

public class Dog {
    private String name;

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

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                '}' + "hashcode = "+hashCode();
    }
}

@Module
public class MainModule {

    @Provides
    Dog provideDog(){
        return new Dog("bob");
    }

}
@Component(modules = MainModule.class)
public interface MainComponent {
    void inject(MainActivity mainActivity);
}
public class MainActivity extends AppCompatActivity {

    @Inject
    Dog dog1;

    @Inject
    Dog dog2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DaggerMainComponent.builder().mainModule(new MainModule()).build().inject(this);
        ((TextView)findViewById(R.id.tv1)).setText(dog1.toString());
        ((TextView)findViewById(R.id.tv2)).setText(dog2.toString());
    }
}

以上代碼中, 沒(méi)有使用@Singleton 修飾, 在MainActivity 中對(duì) Dog進(jìn)行兩次依賴注入, 查看輸出結(jié)果

image.png

可以看出得到的是兩個(gè)Dog對(duì)象, 也就是每依賴注入一次都會(huì)從新調(diào)用一次provideDog方法.
接下來(lái)我們使用@Singleton注解進(jìn)行. 修改其中部分代碼(Module的依賴提供方法上以及Component的類名上)

@Module
public class MainModule {
    
    @Singleton
    @Provides
    Dog provideDog(){
        return new Dog("bob");
    }
}
@Singleton
@Component(modules = MainModule.class)
public interface MainComponent {
    void inject(MainActivity mainActivity);
}

運(yùn)行結(jié)果如下:


image.png

我們可以看到兩個(gè)對(duì)象輸出的hash值相同, 已經(jīng)實(shí)現(xiàn)了一部分的單例, but, 你以為這就實(shí)現(xiàn)了全局單例了么? 我們?cè)賹懸粋€(gè)新的頁(yè)面測(cè)試下!


public class SecondActivity extends AppCompatActivity {

    @Inject
    Dog dog1;
    @Inject
    Dog dog2;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        DaggerMainComponent.builder().mainModule(new MainModule()).build().inject(this);
        ((TextView)findViewById(R.id.tv1)).setText(dog1.toString());
        ((TextView)findViewById(R.id.tv2)).setText(dog2.toString());
    }
}
image.png

我們發(fā)現(xiàn), 雖然provideDog使用@Singleton注解, 但是在不同的頁(yè)面,拿到的依賴對(duì)象仍然不是同一個(gè), 這也就是我們之說(shuō)的局部范圍的單例, 使用@Singeton注解或者定制的@Scope的, 只在同一個(gè)activity(或者fragment)的一個(gè)生命周期中保持單例. 而平時(shí)我們希望一些對(duì)象能夠在整個(gè)應(yīng)用的生命周期中只存在一個(gè), 也就是說(shuō)實(shí)現(xiàn)全局意義上真正的單例該怎么做呢?
DaggerMainComponent在兩個(gè)activity中被各自被實(shí)例化一次, 導(dǎo)致產(chǎn)生了兩個(gè)不同的對(duì)象, 所以我們需要做到讓Component能夠?qū)崿F(xiàn)單例, Android中, 我們知道在整個(gè)App生命周期中都只有一個(gè)Appclication實(shí)例,所以在Application中獲得一個(gè)唯一的component實(shí)例, 用它來(lái)提供我們需要的單例:
代碼如下:

  1. 自定義Application, 并且提供一個(gè)唯一的baseComponent類
public class BaseAppclication extends Application {

    private BaseComponent baseComponent;

    @Override
    public void onCreate() {
        super.onCreate();
        baseComponent = DaggerBaseComponent.builder().baseModule(new BaseModule()).build();
    }

    public BaseComponent getBaseComponent(){
        return baseComponent;
    }
}
  1. 把dog類的依賴提供提取到BaseModule中
@Module
public class BaseModule {

    @Singleton
    @Provides
    Dog provideDog(){
        return new Dog("bob");
    }
}
  1. BaseComponent中不再需要寫inject方法, 因?yàn)檫@個(gè)component是用來(lái)讓別的component來(lái)依賴的, 只需要告訴別的component他可以提供哪些類型的依賴即可, 這個(gè)例子中 我們提供一個(gè)全局Dog的依賴
@Singleton
@Component(modules = BaseModule.class)
public interface BaseComponent {
    Dog provideDog();
}
  1. 在我們自己的Component, 使用dependencies依賴于baseComponent, (在@Component注解參數(shù)中, 可以依賴多個(gè)module和component, 根據(jù)自己的業(yè)務(wù)需求定義即可.)
@ActivityScope
@Component(dependencies = BaseComponent.class)
public interface MainComponent {
    void inject(MainActivity mainActivity);
    void inject(SecondActivity mainActivity);
}

這一步需要注意的是, 這個(gè)component也需要進(jìn)行單例修飾, 但是當(dāng)我們使用@Singleton注解時(shí), 編譯會(huì)報(bào)一個(gè)Error:(14, 1) 錯(cuò)誤: This @Singleton component cannot depend on scoped components, 如果依賴的component中也使用了@singleton時(shí), 被依賴的地方就不能使用了,于是我自定義了一個(gè)Scope: ActivityScope

@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface ActivityScope {
}

好了, 現(xiàn)在準(zhǔn)備工作都做好了, 在頁(yè)面中重新進(jìn)行依賴注入工作,


public class MainActivity extends AppCompatActivity {

   @Inject
   Dog dog1;

   @Inject
   Dog dog2;

   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);
       DaggerMainComponent.builder().baseComponent(((BaseAppclication)getApplication()).getBaseComponent()).build().inject(this);
       ((TextView)findViewById(R.id.tv1)).setText(dog1.toString());
       ((TextView)findViewById(R.id.tv2)).setText(dog2.toString());
   }

   public void click(View v){
       startActivity(new Intent(this, SecondActivity.class));
   }
}

這個(gè)Component在build的時(shí)候需要提供依賴的baseComponent, 此時(shí)我們使用已經(jīng)在baseApplication中已經(jīng)提供的唯一的baseModule, SecondActivity中代碼和上邊差不多, 不貼了. 運(yùn)行查看結(jié)果:

image.png

哈哈, 我們發(fā)現(xiàn)已經(jīng)成功的實(shí)現(xiàn)了單例!!

下篇文章中會(huì)寫到關(guān)于Lazy和Provider的使用.
Dagger2學(xué)習(xí)筆記5(關(guān)于Lazy,Provide的使用)
本文至此, End!~~

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

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

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