Dagger2的简单使用及基本原理

前言

   java注解除了解耦个人认为还有使代码简洁、逻辑更加突出业务逻辑代码、由于创建对象的集中,更加方便对象的维护与测试、对象的创建和生命周期的管控都交由框架等优点。

Dagger2的历史:

  Dagger1是Square公司开发,Dagger2则由谷歌接收在dagger1的分支上开发而来,Dagger1用了反射,消耗了一些性能,Dagger2则被谷歌声称性能提高了13%,但是其灵活性减少

Dagger2的使用

添加依赖:

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

创建一个实体类:

public class DaggerTestBean {
    private String msg="DaggerTestBean注入成功了";

    @Inject
    public DaggerTestBean(){

    }

    public String showMessage(){
        return msg;
    }
}

在构造函数上添加@Inject注解

在需要依赖的类中生命对象:

public class DaggerTestActivity extends AppCompatActivity {
    @Inject
    DaggerTestBean mDaggerTestBean;
    private TextView mTvDagger;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_daggertest);
        mTvDagger = findViewById(R.id.tv_dagger);
        DaggerMainComponent.builder().mainModule(new MainModule()).build().inject(this);
        Log.d("daggerTest", "msg: " + mDaggerTestBean.showMessage());

    }
}

并在声明的对象上添加@Inject注解,仅仅如此还不够

我们需要一个Module,和一个Component类

Module用来声明可以提供哪些实现,如下:

@Module
public class MainModule {
}

这里暂时用一个空的添加了@Module注解的Module类

Component是注解器,链接依赖方和Module,如下:

@Singleton
@Component(modules = MainModule.class)
public interface MainComponent {
    void inject(DaggerTestActivity daggerTestActivity);
}

添加了@Singleton和@Component注解,并指定了modules为MainModule.class,这里是要指明该注入器依赖和被依赖的范围,

需要的模块都建立好了,最后在需要依赖的地方DaggerTestActivity的oncreate中添加注入动作代码:

DaggerMainComponent.builder().mainModule(new MainModule()).build().inject(this);

运行输出:

daggerTest: msg: DaggerTestBean注入成功了

这样简单的使用过程就完成了。

上边的例子是对Bean做了Inject处理,标识可被Module创建对象,也可以在Module中添加提供方法:

@Module
public class MainModule {
    @Provides
    DaggerTestBean provideTestBean(){
        return new DaggerTestBean();
    }
}

这样就不需要在Bean中添加Inject注解了。

Dagger2的原理简单分析

看下编译器做了什么,打开app/build/generated/ap_generated_sources/debug/out/com/modeng/aspro/下多了

在这里插入图片描述

DaggerMainComponent.builder().mainModule(new MainModule()).build().inject(this);

追踪inject,发现逻辑还是挺清晰的,

DaggerMainComponent即为编译器自动生成的规则为Dagger+Component类名的类,看下其inject方法:

@Override
public void inject(DaggerTestActivity daggerTestActivity) {
  daggerTestActivityMembersInjector.injectMembers(daggerTestActivity);
}

调用了daggerTestActivityMembersInjector的injectMenbers方法,看下这个daggerTestActivityMembersInjector对象是什么:

private void initialize(final Builder builder) {

  this.daggerTestActivityMembersInjector =
      DaggerTestActivity_MembersInjector.create(com.modeng.voicecontrolpro.utils.DaggerTestBean_Factory.create());
}

在DaggerMainComponent的initialize方法中创建,其就是编译器生成的DaggerTestActivity_MembersInjector类,看下其injectMembers方法:

@Override
public void injectMembers(DaggerTestActivity instance) {
  if (instance == null) {
    throw new NullPointerException("Cannot inject members into a null reference");
  }
  instance.mDaggerTestBean = mDaggerTestBeanProvider.get();
}

这里有些熟悉的身影了,这里给DaggerTestActivity的mDaggerTestBean赋值了,mDaggerTestBean这个就是咱们添加注解需要注入的对象,继续看下mDaggerTestBeanProvider.get()

public DaggerTestActivity_MembersInjector(Provider<DaggerTestBean> mDaggerTestBeanProvider) {
  assert mDaggerTestBeanProvider != null;
  this.mDaggerTestBeanProvider = mDaggerTestBeanProvider;
}

DaggerTestActivity_MembersInjector在创建的时候给mDaggerTestBeanProvider赋值,继续跟踪

public static MembersInjector<DaggerTestActivity> create(
    Provider<DaggerTestBean> mDaggerTestBeanProvider) {
  return new DaggerTestActivity_MembersInjector(mDaggerTestBeanProvider);
}

来到了DaggerMainComponent类中:

private void initialize(final Builder builder) {

  this.daggerTestActivityMembersInjector =
      DaggerTestActivity_MembersInjector.create(com.modeng.voicecontrolpro.utils.DaggerTestBean_Factory.create());
}

继续看下DaggerTestBean_Factory的create方法,很明显这个是工厂方法:

creat方法拿到的是DaggerTestBean_Factory的实例,通过get方法,拿到创建好的DaggerTestBean对象,至此依赖对象和被依赖对象绑定,完成注入。

public enum DaggerTestBean_Factory implements Factory<DaggerTestBean> {
  INSTANCE;

  @Override
  public DaggerTestBean get() {
    return new DaggerTestBean();
  }

  public static Factory<DaggerTestBean> create() {
    return INSTANCE;
  }
}

Dagger2的其它应用

上边讲的是基本用法了,现在来看下其它一些常用切比较复杂的场景:

1. 需要在不同的条件下获取不同的对象,这个时候用到@Named注解:

  1. 调整下DaggerTestBean:
public class DaggerTestBean {
    private String msg="DaggerTestBean注入成功了,是测试环境";

    public DaggerTestBean(){

    }
    public DaggerTestBean(String a){
        this.msg = a;
    }

    public String showMessage(){
        return msg;
    }
}
  1. 改变下Module:
@Module
public class MainModule {
    @Named("debug")
    @Provides
    DaggerTestBean provideTestBean(){
        return new DaggerTestBean();
    }

    @Named("release")
    @Provides
    DaggerTestBean provideTestBeanWithParams(){
        return new DaggerTestBean("DaggerTestBean注入成功了,是生产环境");
    }
}		
  1. 注入时:
public class DaggerTestActivity extends AppCompatActivity {
    @Named("params")
    @Inject
    DaggerTestBean mDaggerTestBean;
  1. 输出:daggerTest: msg: DaggerTestBean注入成功了,是生产环境

2. Component依赖

添加一个Module:AMoudle

@Module
public class AModule {
    @Named("debug")
    @Provides
    DaggerTestChildBean provideTestBean(){
        return new DaggerTestChildBean();
    }

    @Named("release")
    @Provides
    DaggerTestChildBean provideTestBeanWithParams(){
        return new DaggerTestChildBean("DaggerTestChildBean注入成功了,是生产环境");
    }
}

提供的是DaggerTestChildBean:

public class DaggerTestChildBean {
    private String msg="DaggerTestChildBean注入成功了,是测试环境";

    public DaggerTestChildBean(){

    }
    public DaggerTestChildBean(String a){
        this.msg = a;
    }

    public String showMessage(){
        return msg;
    }
}

当一个Component同时需要MainModule和AModule提供对象时可以有不同的方式:

  1. Comopent注解中添加dependencies参数

    @Singleton
    @Component(modules = AModule.class,dependencies = MainModule.class)
    public interface MainComponent {
        void inject(DaggerTestActivity daggerTestActivity);
    }
    
  2. Module注解中添加include参数

    @Module(includes = AModule.class)
    public class MainModule {
        @Named("debug")
        @Provides
        DaggerTestBean provideTestBean(){
            return new DaggerTestBean();
        }
    
    @Named("release")
    @Provides
    DaggerTestBean provideTestBeanWithParams(){
        return new DaggerTestBean("DaggerTestBean注入成功了,是生产环境");
    }
    
    }
    
  3. Compoent注解中添加Module数组:

    @Singleton
    @Component(modules = {MainModule.class,AModule.class})
    public interface MainComponent {
        void inject(DaggerTestActivity daggerTestActivity);
    }
    

3. 当提供的对象是单利的时候,对应的Component也要是单利

这里要注意,单利是跟着被注入的对象的作用域走的,如果如果被注入到Activity中,作用域是Activity,换到其它Activity就重新创建对象了。

@Singleton
@Component(modules = MainModule.class)
public interface MainComponent {
    void inject(DaggerTestActivity daggerTestActivity);
}
public class DaggerTestActivity extends AppCompatActivity {
    @Named("release")
    @Inject
    DaggerTestBean mDaggerTestBean;
    @Named("release")
    @Inject
    DaggerTestBean mDaggerTestBean1;
Log.d("daggerTest", "msg: mDaggerTestBean的hashCode = " + mDaggerTestBean.hashCode() + " mDaggerTestBean1的hashCode = " + mDaggerTestBean1.hashCode());

​ 输出:daggerTest: msg: mDaggerTestBean的hashCode = 224228315 mDaggerTestBean1的hashCode = 224228315

​ 如果定义在其它Activity:

​ 分别输出:

​ daggerTest: msg: mDaggerTestBean的hashCode = 224228315 mDaggerTestBean1的hashCode = 224228315

​ daggerTest: msg: mDaggerTestBean的hashCode = 12558410 mDaggerTestBean1的hashCode = 12558410

4. 实现真正的全局单利

既然单利跟着作用域走,那么在Application中的对象就应该是在整个app生命周期的单例了。

创建自定义Application,并创建MainCompoent对象:

public class MyApplication extends Application {
    private MainComponent mainComponent;
    @Override
    public void onCreate() {
        super.onCreate();
        mainComponent = DaggerMainComponent.builder().mainModule(new MainModule()).build();
    }

    public MainComponent getMainComponent(){
        return mainComponent;
    }

}

在Activity中拿到MainComponent对象并注入:

((MyApplication) getApplication()).getMainComponent().inject(this);
public class DaggerTestActivity extends AppCompatActivity {
    @Named("release")
    @Inject
    DaggerTestBean mDaggerTestBean;
    @Named("release")
    @Inject
    DaggerTestBean mDaggerTestBean1;
public class DaggerTest1Activity extends AppCompatActivity {
    @Named("release")
    @Inject
    DaggerTestBean mDaggerTestBean;
    @Named("release")
    @Inject
    DaggerTestBean mDaggerTestBean1;

输出:

singleton: onCreate: mDaggerTestBean = 224228315 mDaggerTestBean1 = 224228315

singleton: onCreate: mDaggerTestBean = 224228315 mDaggerTestBean1 = 224228315

可以看到,两个activity的对象都是一样的。

你可能感兴趣的:(andriod,android进阶,java,android,开发语言)