1. 程式人生 > >Android Dagger (二) Provides 、Lazy、Qualifier、Scope 等

Android Dagger (二) Provides 、Lazy、Qualifier、Scope 等

@Provides

上文其實已經講到,這裡重複一下概念

@Provides 可以認為是 @ibject的補充,比如我們使用 OkHttp庫 其他第三庫時,我們並無法直接注入


每定義一個方法,都將生成 獨立的 .java檔案
比如下面程式碼:

- 生成檔案列表
– DemoModule_ProvidePerson1Factory.java
– DemoModule_ProvidePerson2Factory.java
– DemoModule_ProvidePerson3Factory.java

@Module
public class DemoModule {
@Provides Person providePerson1(){ return new Person(); } @Provides Person providePerson2(){ return new Person(); } @Provides Person providePerson3(){ return new Person(); } }

Lazy

延遲注入,其實與 kotlin的 lazy 相同概念

只有在呼叫 Lazy 的 get() 方法時才會初始化依賴例項注入依賴

public class Person {
    @Inject
    Lazy<Car> lazyCar;

    public void goWork() {
        ...
        lazyCar.get().go(); // lazyCar.get() 返回 Car 例項
        ...
    }
}

Qualifier

上面的 DemoModule 提供了三個方法 但是都返回了 Person,
那 dagger 怎麼知道我們要使用哪個返回的Person呢? 在編譯時就會報錯

網上說法,叫依賴迷失, 那如何解決,主人公 Qualifier就派上用場了

module

@Module
public class DemoModule {
    @Provides
    @Named("person1")
    Person providePerson1(){
        return new Person();
    }
    .. 以此類推
}

component

@Component(modules = DemoModule.class)
public interface DemoCompoent {
    void inject(DemoActivity activity);
}

activity

public class DemoActivity extends AppCompatActivity {
    @Inject
    @Named("person1")
    Person person;

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

        DaggerDemoCompoent.create().inject(this);
        // 搞定
 ((TextView)findViewById(R.id.tv_content)).setText(String.valueOf(person.hashCode()));
    }
}

Scope <作用域>

Scope 是用來確定注入的例項的生命週期的,如果沒有使用 Scope 註解,Component 每次呼叫 Module 中的 provide 方法或 Inject 建構函式生成的工廠時都會建立一個新的例項

這裡寫圖片描述
我們先來設想下這樣的場景
這裡寫圖片描述
顯然如果我們不做任何處理 @Inject注入,每個人都會有一輛車。
那麼如何避免? Scope 來了~

定義物件

public class Wang {
    Car car;

    public Wang(Car car) {
        this.car = car;
        System.out.println("我是王 我的車子物件是 -> " + car.hashCode());
    }
}

public class Zhang {
    Car car;

    public Zhang(Car car) {
        this.car = car;
        System.out.println("我是張 我的車子物件是 -> " + car.hashCode());
    }

}

scope

固定格式,主要是名字 跟 使用位置區分

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

module

@Module
public class CarModule {

    @Provides
    @CarScope  // 自定義作用域,可以嘗試註釋掉,然後最後輸出就變為了三個car
    Car provideCar(){
        return new Car();
    }
}

@Module
public class DemoModule {

    @Provides
    Zhang provideZhang(Car car){
        return new Zhang(car);
    }

    @Provides
    Wang provideWang(Car car){
        return new Wang(car);
    }

}

DemoComponent

@Component(modules = {
        CarModule.class,
        DemoModule.class
})
@CarScope   // 必須與 module provide限制相同,否則編譯不通過
public interface DemoComponent {
    void inject(DemoActivity activity);
}

Activity使用

public class DemoActivity extends AppCompatActivity {
    @Inject
    Zhang zhang;
    @Inject
    Wang wang;
    @Inject
    Car car;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_demo);
        DaggerDemoComponent.create().inject(this);
        System.out.println("car --> " + car.hashCode());
    }
}
// 輸出結果
我是張 我的車子物件是 -> 237250545
我是王 我的車子物件是 -> 237250545
car --> 245728614

這樣也就確保了,只有一輛車