Dagger2的使用

前言

  • 注解如同标签
  • 反射:GreenDao、Butterknife、Dagger2 这些因为涉及到了反射处理,而反射处理相对于正常开发速度很慢,所以它们通常在编译时产生一些新的代码,然后才能在程序运行过程中使用,也就是说它们都把反射处理移动到编译器编译代码时的阶段,而程序运行时并不涉及到反射,这就是这些框架运用了反射技术,但是仍然高效的秘诀所在。
  • 要先编译一次代码,不然就会报错。现在,可以解释了,编译代码是为了生成中间代码,然后在中间代码的基础上按照正常的流程开发。

依赖注入

class A {
    B b;
    C c;

    public A() {
        b = new B();
        c = new C(3);
    }
}
//————————————————
class A {
    B b;
    C c;

    public A(B b, C c) {
        this.b = b;
        this.c = c;
    }
}
/**
* 在上面代码中,A 不再直接创建 B 与 C,它把依赖的实例的权力移交到了外部,所以无论 B 和 C 怎么变* * 化,都不再影响 A 了。     
* 这种实例化依赖的权力移交模式被称为控制反转(IoC)      
* 而这种通过将依赖从构造方法中传入的手段就是依赖注入(DI)
*/

依赖注入的3种形式

构造方法注入

class A {
    B b;
    public A(B b) {
        this.b = b;
    }
} 

Setter 注入

class A {
    B b;
    public void setB(B b) {
        this.b = b;
    }
}

接口注入

interface Setter {
    void setB(B b);
}

class A implements Setter{
    B b;
    public void setB(B b) {
        this.b = b;
    }
}

Dagger2

依赖注入框架
通过注解标记,Dagger帮我们完成实例化和注入。
Dagger2本质就是, 一个依赖注入框架,用来解耦。

@Inject

标记

  • 给属性做标记时:依赖的需求方(需求者)
  • 给构造方法做标记时:依赖的提供方(依赖)
public class Man {
    @Inject
    FoodRice foodRice;
    
    @Inject
    public Man() {}
}

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

@Component

联系纽带,将 @inject 标记的需求方和依赖绑定起来,并建立了联系,
Dagger2 在编译代码时会依靠这种关系来进行对应的依赖注入

@Component()
public interface ManComponent {
    Man getMan();
}

//build:makeBuild --> project模式 --> app --> build --> generated --> source --> apt --> debug

//DaggerManComponent.builder().build().getMan().toString();

@Provides 和 @Module

  • Inject只能标记在我们自己写的类中,如果要提供第三方作为依赖对象就需要@Provides和@Module了
  • @Provides 注解的依赖必须存在一个用 @Module 注解的类中
  • 除了第三方无法Inject标记的在Module中提供,一些需要生成对象以后做其它初始化操作的也适合写到Module中
//没有提供Inject标记,视为无法改变的第三方类
public class LibClass {
    @Override
    public String toString() {
        return "第三方类,不可修改\n";
    }
}

@Module
public class ManModule {
    @Provides
    public LibClass provideLibClass(){
        return new LibClass();
    }
}

//在Component中关联该Module
@Component(modules = ManModule.class)
public interface ManComponent {
}

public class Man {
    @Inject
    LibClass libClass;
}

无法控制生成实例的类进行依赖

  • 系统生成实例的类进行依赖,如Activity
/*
* 无法控制生成实例
*/
@Component(modules = ManModule.class)
public interface ManComponent {
    void inject(DaggerMainActivity activity);
}

public class DaggerMainActivity extends BaseActivity {
    @Inject
    Man man;

    protected void initData() {
        DaggerManComponent.builder().build().inject(this);
        man.toString();
    }
}

实例需要特殊处理

public class FoodRiceEgg extends FoodRice {
    private String mType = "";
    public FoodRiceEgg() {}

    public void setType(String type){
        this.mType = type;
    }

    @Override
    public String toString() {
        return "食物:"+mType+"蛋炒饭;\n";
    }
}

@Module
public class ManModule {
    @Provides
    public FoodRiceEgg provideFoodRiceRegg(){
        FoodRiceEgg riceEgg = new FoodRiceEgg();
        riceEgg.setType("金色的");
        return riceEgg;
    }
}

public class Man {
    @Inject
    FoodRiceEgg foodRiceEgg;
}

// 1. FoodRiceEgg extends FoodRice, 构造函数未改变,继承父类注解,所以这里不需要@Inject
// 2. Man中foodRiceEgg可以通Inject注解生成,也可通过Module获得,Module优先级高

提供依赖和注入的方式

提供依赖

  • Inject标识构造方法
  • 在Module中@Provide提供
    (Inject标识和Module中提供相同的依赖,以Module中优先)

@Component注入依赖(纽带)

注入的方式有两种:

  • 有Inject标识的返回该类型
  • 无法控制生成实例的,作为参数传入,进行依赖(如Activity)
@Component()
public interface ComponentTest {
    Man getMan();
    void inject(Activity act);
}

@Singleton 引出 @Scope

@Singleton
public class SingleBean {
    @Inject
    public SingleBean() {
    }
}

//另外也可在Module中以Provide的方式提供
@Module
public class SecondActivityModule {
    @Provides
    @Singleton
    public TestSingleton provideTestSingleton(){
        return new TestSingleton();
    }
}



@Singleton
@Component(modules = ManModule.class)
public interface ManComponent {
    Man getMan();
    void inject(DaggerMainActivity activity);
}

// Man和Activity中Inject标注的实例就是单例的

@Scope

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

//@Singleton 所拥有的单例能力是以 Component 为范围的限定的
//@Singleton 起作用是因为它被 @Scope 注解。所以,我们也可以自己定义 Scope
//例如:以@PageScope来限定某一个依赖的作用域

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

@Named和@Qualifiers

同类型、不同实例:

在Module中Dagger是根据返回类型确定要提供的依赖
如果是同类型不同实例,那就会混乱了

public class Man {
    @Inject
    @Named("name")
    String name;

    @Inject
    @StrPhone
    String phone;
}

@Module
public class ManModule {
    //1.@Named标注
    @Provides
    @Named("name")
    public String provideName(){
        return "Varmin";
    }
    
    //2. 自定义注解
    @Provides
    @StrPhone
    public String providePhone(){
        return "13439251326\n";
    }
}

@Qualifier

//@Name 只是被 @Qualifier 注解的一个注解。所以,它能够有效完全是因为 @Qualifier
//所以,我们也可以@Qualifier为元注解自定义注解,来区分同类型不同实例提供依赖时的区分

@Qualifier
@Documented
@Retention(RUNTIME)
public @interface Named {
    String value() default "";
}

@Qualifier
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface StrPhone {
}

Component依赖

依赖:所以需要暴露接口
A依赖B,A想使用B的属性,就需要注入B的实例,并且B提供接口暴露出来

@Module
public class JobModule {
    @Provides
    public Coder provideCoder(){
        return new Coder();
    }
}

@Component(modules = JobModule.class)
public interface JobComponent {
    //自用无需写,被依赖需显示提供
    Coder getCoder();
}

//这里如果只是想复用Coder,也可以直接使用多个Module,不必使用依赖的概念
//@Component(modules = {ManModule.class, JobModule.class}) 
@Component(modules = ManModule.class, dependencies = JobComponent.class)
public interface ManComponent {
    Man getMan();
}

public class Man {
    @Inject
    Coder coder;
}

DaggerManComponent.builder()
        .jobComponent(jobComponent).build()
        .getMan();

/**
* 如果只是在DaggerJobComponent中使用Coder,因为有JobModule,所以那直接用就好了,不用在Component中显示提供接口。
* 但是在DaggerManComponent中,Coder是来自于依赖的JobComponent所有
* DaggerManComponent中需注入JobComponent实例,并通过实例中的接口获得Coder
*/

Component继承

继承:子类可以获取到父类能提供的所有类型
子类:用@Subcomponent标记
父类:返回SubComponent getSubComponent()类型

@Component(modules = ManModule.class)
public interface ManComponent {
    SubComponent getSubComponent();
}

@Subcomponent()
public interface SubComponent {
    Man getMan();
    void inject(DaggerMainActivity activity);
}

//Activity
@Inject
FoodRice foodRice;
...
@Inject
@Named("name")
String name;
DaggerManComponent.builder()
        .getSubComponent()
        .inject(this);

// 在Activity中getSubComponent可以获取到ManComponent可提供的所有类型

Component生命周期

onCreate()中inject()方法调用完成后,Component实例就会因为没有被引用而被垃圾回收器回收.
需要注意的是,使用Lazy和Provider时,与该依赖对象有关的Module实例会被Lazy和Provider引用,所以该Module实例不会被垃圾回收器回收

懒加载、强制刷新

@Inject
Lazy<LazyBean> lazyBean;
@Inject
Provider<RefreshBean> refreshBean;

lazyBean.get()
refreshBean.get()
refreshBean.get()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值