注入神器Dagger2-----基本使用及原理分析(一)

Dagger2是一个实现注入的框架,相信大家都听说过ButterKnife,Dagger2和ButterKnife的作用是一样的,但是实现的功能更加强大。ButterKnife只能注入View和事件,而Dagger2可以注入任何一个对象。本节主要介绍一下Dagger2的实用及实现的原理。

一、Dagger2的使用

首先我先用张图来简单说明一下Dagger2使用的流程

图中的Module是应用中常用的功能模块,比如说网络访问,数据存储等。这个类会有一个@Module的注解,具体的代码我会在后面详细介绍。其实这个Module的作用是提供各种功能对象,而这些Module会放到一个有@Component的容器类中,也就是图中Component类。当我们想使用各种功能对象进行业务操作的时候,只需要这个容器就能得到被注册了的功能对象,图中的意思是在Activity中使用对象进行业务操作,当然也不仅限于Activity。

上图相对来说还是太简略了,并没有完整的表达出Dagger2的原理,下面我们直接从代码中感受一个Dagger2的强大。

1.引入Dagger2

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

2.创建网络访问对象及其Module模块

首先创建一个HttpObject,我们假设这个HttpObject中有各种网络的操作,get,post,put等

public void get(){
        Log.i("Dagger2","这里是get方法");
    }
    
    public void post(){
        Log.i("Dagger2","这里是post方法");
    }
}

创建HttpModule

@Module
public class HttpModule {
    @Provides
    public HttpObject providerHttpObject(){
        return new HttpObject();
    }
}

HttpModule的两个注解是需要注意的地方:@Module这个注解相当于给当前类打了一个标记,表明了这个类的类型,便于注入到容器中;@Provides这个注解放在了方法的上面,从上面的代码可以看出来,主要就是创建功能对象。

3.创建容器Component

@Component(modules = {HttpModule.class})
public interface MyComponent {
    void injectMainActivity(MainActivity mainActivity);
}

容器这个类被@Component所注解,而且是一个接口类,@Component中的modules参数接收的类型是一个数组,表示被装入容器的Module有哪些。injectMainActivity方法表示这个容器中的功能对象(例如HttpObject)会在哪个类使用,我这里使用的MainActivity做的测试,所以参数写的是MainActivity。

4.在类中使用HttpObject

在配置完上述的代码之后,一定先rebuild!

public class MainActivity extends AppCompatActivity {
    @Inject
    HttpObject mHttpObject;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DaggerMyComponent.create().injectMainActivity(this);
        mHttpObject.get();
        mHttpObject.post();
    }
}

因为我们要使用的类是HttpObject,所以在MainActivity创建这个类的对象,然后被@Inject所注解。要注意的是DaggerMyComponent这个类是rebuild之后生成的,调用DaggerMyComponent.create().inkectMainActivity(this)这句话来生成mHttpObject对象,调用HttpObject中的get和post方法就会有相应的输出。

Dagger的优点

有的小伙伴会问,你整这么一大堆是为了啥?要不然直接创建对象,要不然创建一个单例,多省事,可比Dagger2的这种方式方便多了。在中大型项目中,类似于HttpObject这种对象会被大量的应用,如果突然有一天这个类的初始化方法改变了,你岂不是要修改每一处吗。即便是使用单例getInstance方法也避免不了这种问题,因为如果在创建对象的时候需要在构造器中添加一个参数,每一处的getInstance也需要被修改。而Dagger2完美的避免了这种问题

二、源码分析

下面我们从源码中分析Dagger2的实现流程

上面的代码我们使用了create方法来创建MyComponent,这次我们使用建造者的方式来创建,Dagger2中提供了这种方式,如下代码

DaggerMyComponent
                .builder()
                .httpModule(new HttpModule())
                .build()
                .injectMainActivity(this);

其实我们从create的方法中进入就可以看到,其实create中包装了建造者的方式。

builder方法其实没什么说的,点进去看,其实就是Builder的创建,代码我就不贴出来了。

httpModule这个方法肯定就是相应Module的创建了,代码如下,我们可以看出来,源代码中只是做了一个对象非空的检查

public Builder httpModule(HttpModule httpModule) {
      this.httpModule = Preconditions.checkNotNull(httpModule);
      return this;
}

而build方法主要就DaggerMyComponent的创建,代码如下:

public MyComponent build() {
      if (httpModule == null) {
        this.httpModule = new HttpModule();
      }
      return new DaggerMyComponent(this);
}

以上的代码都没什么特别的,主要就是建造者模式的只用,下面我们来分析一下injectMainActivity方法的逻辑。

我们点击进入injectMainActivity这个方法,会进入到我们所写的MyComponent这个接口方法中,点击图中红框的位置会出现接口的实现类或者直接进入到实现类

MyComponent的实现类其实我们已经见到了,就是DaggerMyComponent,其中injectMainActivity的实现方法如下:

@Override
  public void injectMainActivity(MainActivity mainActivity) {
    mainActivityMembersInjector.injectMembers(mainActivity);
  }

mainActivityMembersInjector的类是MembersInjector<T>这个接口类,同样的我们查看这个方法的实现类方法:

我们发现实现类有两个,那我们查看哪个呢?我们来这样看:首先将项目切换到project模式,依次进入如下目录:app->build->generated->source->apt->debug,到这里,我们就发现了我们项目的包,可以看见生成了几个类,如图:

而图中红框标注的正是MembersInjector<T>的实现类,我们想要找的就是它,我们来查看injectMembers方法的实现:

 private final Provider<HttpObject> mHttpObjectProvider;

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

代码中的instance是MainActivity,而mHttpObject是MainActivity中的mHttpObject(从这里我们可以看出来,想要被注解的对象修饰符一定是public),mHttpObject是通过mHttpObjectProvider.get()获得的,mHttpObjectProvider的类是Provider,而Provider是一个接口,我们如果还是使用上面的方法来找实现类,你会发现实现类有四五十个,那怎么办呢?

从上面系统帮我们生成的类中有如下这么一个类,而这个类这是我们想要找的Provider的实现类,我们点击去查看get方法的实现:

@Override
  public HttpObject get() {
    return Preconditions.checkNotNull(
        module.providerHttpObject(), "Cannot return null from a non-@Nullable @Provides method");
  }

get方法所返回的是module通过providerHttpObject方法创建的,这个module是HttpModule,点击去查看providerHttpObject:

@Module
public class HttpModule {
    @Provides
    public HttpObject providerHttpObject(){
        return new HttpObject();
    }
}

这个不就是我们的HttpModule中的方法吗?是的,Dagger框架绕了一大圈创建了HttpObject这个对象。

以上就是Dagger创建对象的流程

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值