Dagger2基础的使用

前言

    

    

        Dagger2的介绍和配置

        Dagger2基础的使用

        Dagger2进阶-编译生成源码解读

        Dagger2进阶-范围的控制(Scope和Singleton)

        Dagger2进阶-Scope的源码探究

        项目源代码传送门


    这篇文章主要说关于Dagger的应用基础。

基础的注解解释

    Dagger2是一种注解型框架,使用注解在编译期生成固定的代码模板完成对象的创建,和目标对象的依赖关系。

    限于篇幅,我们先来说4个注解,只要有这4个注解我们就能完成大部分应用场景。

    @Inject:翻译为注入,该注解在javax包中,不是Dagger独有的注解,在Dagger中作用于构造方法和字段中,作用在构造方法中会解析生成一个类的工厂模板对象,表示提供该类的实例,作用在字段中表示创建一个对象得到一个对象实例。

    @Inject 提供类有以下限制:

      1、因接口没有构造方法,无法使用,在程序中无法使用接口编程的思想是很可怕的。

      2、在使用第三方对象的时候,我们无法直接修改别人对象的源码,所以用构造方法也不现实。

      3、还有一些就是比较特殊的类,使用建造者模式开发的这种用来配置生成对象的,构造方法本身就是被禁的。

    @Component:翻译为组件,在Dagger中@Component的作用就是关联,比如我们Activity中需要一个Goods商品对象,而如果只用 @Inject是不行的,因为  @Inject作用在Goods的构造方法中的时候,只是提供了一个工厂类,而作用在Acivity的字段也只是告诉解释器Activity需要这个对象却没有进行关联操作,@Component会为程序生成一个提供Activity和Goods工厂类相关联的管道的类。没有Component编辑的时候不会报错,但是对象肯定是null的。

    @Module:模块,作用在类中,是为了解决@Inject的局限性而Dagger加入的独有注解,也是为生成对象而生的,他配合@Provides使用,还有就是用来区分模块,比如网络、db、Sp等都有自己需要生成的类,我们总能放在一个类中吧,他跟@Provides是一对多的关系,@Provides不能脱离他实现,否则会报错。

    @Provides:提供类,只能作用在方法中,不能作用在没有@Module注解的类的方法中,否则会报错:Error:(18, 18) 错误: @Provides methods can only be present within a @Module or @ProducerModule,其作用跟@Inject一样也是生成工厂类。


    基础概念已经说完了,但是看得是云里雾里,需要更深入的了解Dagger我们需要一些例子进行辅助。

生成一个简单的对象 @Inject 

    现在我有一个需求,我需要一个没有任何数据的Goods商品对象如何获取,当我们没有学过Dagger2的时候我们会直接new一个,拥有了Dagger2这把武器,我们将使用另一种方式进行new新操作。

    创建一个无参数的构造方法的类,并使用@Inject 修饰构造方法:

    @Inject
    public Goods(){

    }

    然后当我们需要在Activity中使用时,只需要添加代码如下:

    

@Inject
Goods mGoods;

  

 接下来我们建立一个没有module的component:

@Component
public interface MainActivityComponet {

    void inject(MainActivity activity);
}

 接下来,我们对工程项目进项make project一下,编译后,可以查看build->generated->source->apt

->debug(release)->项目包->找到生成的文件,假设没有生成,查看是否报错,若没有报错查看配置是否添加了apt,这里我们主要的关注Component生成的类,以Dagger+xxx(Component)命名,这里我的项目生成DaggerMainActivityComponet这个类,这个类就是我们用来关联Activity和Goods的。编译图如下:


最简单的也是生成了三个类,我们说说他们的作用:

XX_Factory的作用是XX类的工厂类

Dagger+xx是根据Componet组件生成的,其作用是关联工程类和XXX_MembersInjector这个类,

XXX_MembersInjector这个类是通过Activity中的字段@Inject生成的

这里先简单的说一下,当然只有真正的去看源码才能更好的学习Dagger2,后面会更新源码解读。

最后一步,在Activity中使用Dagger+XX告诉框架,需要使用对象的是那个类:

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

        DaggerMainActivityComponet
                .builder()
                .build()
                .inject(this);

        Log.d(TAG,mGoods.toString());
    }
运行后发送,Log可以打印出Goods对象的引用地址,说明Goods已经new了一个对象

生成一个带有依赖的对象

先说一下需求:

    比如,假设订单跟商品是一对一的关系,我需要一个没有数据的订单对象,怎么做?

    我们先创建一个订单类:

    

public class Order {

    @Inject
    public Order(Goods mGoods) {
        this.mGoods = mGoods;
    }

    private Goods mGoods;
}

在Activity中使用对象:


这个订单类只是加一个商品的对象字段,之前的代码不动,然后编译。


跟之前编译的图片进行对比,不考虑内部实现的情况下,只是增加了一个Order_Factory,打印Log如下:


看Log对象生成了,我们什么都没做,只是建了一个订单类,就订单的生成了Order对象,并且自动装配需要依赖的对象,就像是有一个对象池一样,Order告诉对象池,我需要一个Goods类,你给我一个呗,对象池就负责生成一个对象给Order类。

生成一个第三方对象 @Module和@Provides

    根据之前的两个注解,其实我们就已经能完成普通对象的创建工作,但是当我们需要创建一个自己写的Sdk对象或者第三方的对象的时候,我们不能去改之前的代码吧,所以@Module和@Provides就应运而生了,下面我们来创建一个Gson对象:

    首先我们需要明确,我们需要建立什么对象,比如需要一个Gson类,平时我们需要一个Gson对象,就是直接Gson mGson=new Gson(),没有任何依赖。

    第二步,我们创建一个Module类,比如XXX_Module,这里对类名不做要求,但是为了更好区分建议大家这样命名,然后编写代码如下:

    

@Module
public class ObjectModule {

  @Provides
  public Gson provideGson(){
      return new Gson();
  }

ObjectModule类中,使用@Provdes修饰一个方法,生成一个新建一个Gson.

    第三步,我们需要告诉组件Component,我们需要一个Module,这个Module叫什么名字,MainActivityComponet修改如下:

    

@Component(modules = ObjectModule.class)
public interface MainActivityComponet {

    void inject(MainActivity activity);
}

就是在@Component标签中添加modules的赋值,Activity修改如下:

@Inject
Gson mGson;
 DaggerMainActivityComponet
                .builder()
                .objectModule(new ObjectModule())
                .build()
                .inject(this);

这里多了一句objectModule(new ObjectModule()),这是为组件注入ObjectModule对象,运行完成。这里需要注意一下,component中每一个需要到的Module都是注入到component中。


常见问题:

1.@Inject修饰对象不能是私有的privated,否则会报错:Error:(13, 20) 错误: Dagger does not support injection into private fields

2.类没有使用@Module注解但是方法中使用了@Provides注解报错:Error:(18, 18) 错误: @Provides methods can only be present within a @Module or @ProducerModule

3.当我们设置了在目标类中设置了@Inject字段 并且@Component,@Module的时候,程序扫描不到生成的对象时:

Error:(21, 10) 错误: com.lyc.love.dagger2demo.bean.Goods cannot be provided without an @Inject constructor or from an @Provides- or @Produces-annotated method.
com.lyc.love.dagger2demo.bean.Goods is injected at
com.lyc.love.dagger2demo.MainActivity.mGoods3
com.lyc.love.dagger2demo.MainActivity is injected at

com.lyc.love.dagger2demo.dagger2.component.MainActivityComponet.inject(activity)

这种错误,要我们去检查一下@Module是都提供了@Provides注解。

4.当使用Module的传入Module的时候方法变成遗弃@deprecated 标志,并且描述为This module is declared, but an instance is not used in the component. This method is a no-op. For more, see https://google.github.io/dagger/unused-modules.这是因为,在Activity中没有使用Module中的任何对象,所以编译的时候,框架标注为不需要使用。加上重新编译就好了。

5. Error:(15, 1) 错误: com.chipsea.yilianintelligence.mydevice.dagger.component.MyDeviceComponent (unscoped) may not reference scoped bindings 因为Mudle设置了Scope范围,而Compoenent没有设置导致的。

猜你喜欢

转载自blog.csdn.net/u010782846/article/details/79826483