前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Dagger2 Android依赖注入学习笔记

Dagger2 Android依赖注入学习笔记

作者头像
砸漏
发布2020-11-05 14:50:54
6730
发布2020-11-05 14:50:54
举报
文章被收录于专栏:恩蓝脚本

前言

最近在用 MVP + RxJava + Retrofit 写项目,觉得相对于其他的开发框架,这的确是给我们带来了很多方便,但是在网上搜寻相关资料的时候,总是能看到 MVP + RxJava + Retrofit + Dagger 这样的搭配组合,那 Dagger 又是一个怎样的框架呢,我也去具体搜了搜,但看到一些文章带着“Dagger2从入门到放弃”这样意思的句子,就感觉Dagger2会很难吗,emmmm…行吧,好像是有点难理解,但是想着既然有那么多人用这个框架,必然有它的好处,于是花了些时间学习了一波。

Dagger2

Dagger2 : A fast dependency injector for Android and Java. (官方给出的定义)

Dagger2是一个依赖注解框架,它的作用就是通过注解来实现组件之间的依赖,由此来达到更好的解耦,比如说,如果将 Dagger2 使用到我们的 MVP 框架中,那么我们就可以达到 V层 和 P层 的进一步解耦,从而使我们的项目有更好的维护性。

Dagger2 和 Butterknife 一样,都是在编译阶段利用Java注解通过APT(Annotation Processing Tool)自动生成Java代码,然后由我们自己写的代码进行调用,完成依赖注入,因此不用担心性能上的问题。那么如何来使用 Dagger2 呢?我们先来看一下使用 Dagger2 和不使用的区别。

对比

用简单的例子来说明。比如说我们有这样一个AAA类,没什么内容,只有一个get()方法

代码语言:javascript
复制
/**
 * @author chaochaowu
 * @Description : AAA
 * @class : AAA
 * @time Create at 6/12/2018 10:58 AM
 */

public class AAA {

 
 public AAA() {
 }

 public void get(){
  Log.e("AAA","has gotten.");
 }

}

我们需要在MainActivity用到这个类,因此MainActivity中变含有这个成员变量,有了这个成员变量aaa,我们就要对它进行实例化,因此会有以下的代码:

代码语言:javascript
复制
/**
 * @author chaochaowu
 * @Description : MainActivity
 * @class : MainActivity
 * @time Create at 6/12/2018 10:58 AM
 */
public class MainActivity extends AppCompatActivity {

 AAA aaa;

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

  aaa = new AAA();
  aaa.get();

 }
}

我们需要在 MainActivity 中声明aaa这个变量,然后会对其进行new一个实例,然后才能对其进行调用,调用它定义的方法。这样,AAA类对象的创建就和 MainActivity 耦合在了一起。如果使用 Dagger2 进行依赖注入呢

代码语言:javascript
复制
/**
 * @author chaochaowu
 * @Description : MainActivity
 * @class : MainActivity
 * @time Create at 6/12/2018 10:58 AM
 */
public class MainActivity extends AppCompatActivity {

 @Inject
 AAA aaa;

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

  DaggerMainActivityComponent.create().inject(this);
  
  aaa.get();

 }
}

代码就会变成这样。我们可以发现MainActivity里没有任何有关aaa的初始化赋值,但是它还是可以调用其get()方法。这样我们就达到了解耦合的目的。

这样一个简单的例子可能看不出 Dagger2 的好处,但是你可以想象一下,如果这个 Activity 里有很多个类似 AAA 这样的类的成员变量,它们都需要初始化,有的初始化还要传参数,那么,这个 Activity 就会变得臃肿,如果 AAA类 的初始化参数变了,不仅 AAA类 需要改,MainActivity 因为它与AAA类的耦合也要跟着改变,如果 AAA类 不止用在 MainActivity 中还用在了其他的 Activity 中,那么要改的东西变的可有点多咯,但是如果用上Dagger2,我们就可以很好的解决这个问题。

注解介绍

Dagger2中注解有:@Inject, @Component, @Module, @Provides, @Qulifier, @Scope, @Singleten 。而我们主要用到的是@Inject, @Component,@Module, @Provides 这四个,下面来介绍一下。

@Inject

Inject 主要用来标记需要依赖的变量,告诉Dagger需要为它提供依赖;inject 还被用来标记类的构造函数。当Dagger2碰到使用@Inject注解的变量时,会去寻找这个变量对应的被@Inject注解的构造函数,把实例构造出来,为变量提供依赖。

@Component

@Component用于标注接口,是依赖需求方(MainActivity)和依赖提供方(AAA)之间的桥梁。被Component标注的接口在编译时会生成该接口的实现类,类的名称为被@Component注解的类的名称前加上Dagger,我们通过调用这个实现类的方法来完成注入。

@Module

Module用于标注提供依赖的类。虽然我们有@Inject注解实现注入,但是@Inject只能注入构造函数为无参的类,要是构造函数是带参数的呢?那就要使用module注解来解决这个问题,又比如说,有很多的第三方库,我们对它的代码无法进行修改,也就不能对其构造函数加上@Inject注解,那么可咋办啊,@module注释可以很好的解决我们的问题。

@Provides

Provides是与Module一起使用的,@Provides用于标注Module所标注的类中的方法,该方法会在需要提供依赖时被调用,在方法内进行对象的初始化,返回对象依赖给标注了@Inject的变量。相当于一个有参数的@Inject。

我们来具体的使用一下。

构造函数无参的对象注入

用上面提到的 AAA类 进行依赖注入演示。

首先我们在 AAA类 的构造函数上加上 @Inject 注解(构造函数必须得是无参)

代码语言:javascript
复制
/**
 * @author chaochaowu
 * @Description : AAA
 * @class : AAA
 * @time Create at 6/12/2018 10:58 AM
 */


public class AAA {

 @Inject
 public AAA() {
 }

 public void get(){
  Log.e("AAA","has gotten.");
 }

}

然后创建一个 MainActivityComponent 接口并用 @Component 进行注解,然后Build一下项目,

代码语言:javascript
复制
/**
 * @author chaochaowu
 * @Description : MainActivityComponent
 * @class : MainActivityComponent
 * @time Create at 6/12/2018 11:03 AM
 */

@Component
public interface MainActivityComponent {
 void inject(MainActivity mainActivity);
}

Build之后apt会自动生成如下的代码

build后生成.png

我们利用其中的 DaggerMainActivityComponent 进行 MainActivity 与 AAA类 之间的桥梁搭建。如下代码

代码语言:javascript
复制
/**
 * @author chaochaowu
 * @Description : MainActivity
 * @class : MainActivity
 * @time Create at 6/12/2018 10:58 AM
 */
public class MainActivity extends AppCompatActivity {

 @Inject
 AAA aaa;

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

  DaggerMainActivityComponent.create().inject(this);

  aaa.get();

 }

}

至此,我们便完成了构造函数无参的对象的依赖注入。

构造函数含参的对象注入

相信很多的时候,我们要用的对象在构造的时候是需要参数的,那我们如何进行它们的依赖注入呢,这里我用 MVP 中的 Presenter 来进行演示。

代码语言:javascript
复制
/**
 * @author chaochaowu
 * @Description : MainActivity
 * @class : MainActivity
 * @time Create at 6/12/2018 10:58 AM
 */
public class MainActivity extends AppCompatActivity implements MainContract.View{
 
 MainContract.Presenter mPresenter;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  
  mPresenter = new MainPresenter(this);
  mPresenter.getData();

 }

}

上面的代码是没用 Dagger2 时的 Activity,在 MVP 框架中,由于 Presenter 需要与 View 进行交互,需要持有View的对象,因此在初始化的时候,需要在构造函数里传入View对象作为参数,可以看到代码中 mPresenter = new MainPresenter(this);

接下来我们对它进行依赖注入。首先看一下 Presenter,,Presenter不需要作出任何改变,我们可以看到它的构造函数带有一个参数View

代码语言:javascript
复制
/**
 * @author chaochaowu
 * @Description : MainPresenter
 * @class : MainPresenter
 * @time Create at 6/11/2018 2:22 PM
 */
public class MainPresenter implements MainContract.Presenter{
 MainContract.View mView;
 public MainPresenter(MainContract.View mView) {
  this.mView = mView;
 }

 @Override
 public void getData() {

 }
}

然后我们需要创建一个 MainActivityModule 类,并在该类名加上@Module注解,它含有一个成员变量 mView 需要在构造函数时赋值,我们之后会将这个变量给 Presenter 进行 Presenter 的构造,我们还需要写一个方法,并在其上添加@Provides注解,方法的名字其实没所谓可以随便取,但是为了代码的可读性,一般都以provide开头加上provide的东西的名字,我们在这个方法里返回我们所要提供依赖的对象,这里返回了一个 Presenter 对象,可以看到它在这里的构造,我们传入了参数 View。到这便完成了MainActivityModule 的定义,其实这个 MainActivityModule 作用就和之前的 构造函数无参中的 对无参构造函数 Inject 步骤的性质相同。

代码语言:javascript
复制
/**
 * @author chaochaowu
 * @Description : MainActivityModule
 * @class : MainActivityModule
 * @time Create at 6/11/2018 2:41 PM
 */
@Module
public class MainActivityModule {
 MainContract.View mView;

 public MainActivityModule(MainContract.View mView) {
  this.mView = mView;
 }
 @Provides
 public MainContract.Presenter providePresenter(){
  return new MainPresenter(mView);
 }
}

接下来和 构造函数无参的对象注入 中一样,我们需要定义一个 MainActivityComponent ,并用 @Component 进行注解,不一样的是需要在括号里加上参数 modules = {MainActivityModule.class} 如下代码。

代码语言:javascript
复制
/**
 * @author chaochaowu
 * @Description : MainActivityComponent
 * @class : MainActivityComponent
 * @time Create at 6/11/2018 2:45 PM
 */
@Component(modules = {MainActivityModule.class})
public interface MainActivityComponent {
 void inject(MainActivity mainActivity);
}

Build一下项目

build之后生成.png

这样我们就可以像上面一样,在Activity中调用DaggerMainActivityComponent 进行依赖注入。看一下Activity中的代码。

代码语言:javascript
复制
/**
 * @author chaochaowu
 * @Description : MainActivity
 * @class : MainActivity
 * @time Create at 6/12/2018 10:58 AM
 */
public class MainActivity extends AppCompatActivity implements MainContract.View{

 @Inject
 MainContract.Presenter mPresenter;

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

  DaggerMainActivityComponent.builder()
    .mainActivityModule(new MainActivityModule(this))
    .build()
    .inject(this);

  mPresenter.getData();

 }
}

可以看到这里 DaggerMainActivityComponent 调用的方法有所不同,其中调用了一个mainActivityModule() 方法,传入了一个 MainActivityModule 对象,该对象的初始化,我们又传入了一个this,也就是View,这个 View就是我们在之后创建 Presenter 时传入的参数 。

至此,我们就完成了构造函数有参的对象的依赖注入。其他有参的、第三方库的依赖注入也是通过这样的方式进行。

总结

Dagger2的使用,让我们代码的耦合度进一步降低了,这是一个优点,但是另一方面,使用了Dagger2你需要额外的去定义一些类,导致代码的数量也增加。个人觉得,在比较小的项目中,如果去使用,有点emmmm….多此一举?(划掉),但是如果一个项目比较大,代码本身也比较多,那么使用Dagger2所带来的优点,便可以显现了。所以说,是否在项目中使用 Dagger2 仁者见仁智者见智,不过作为一个学习的点,还是挺不错的,嗯。

以上就是本文的全部内容,希望对大家的学习有所帮助。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-09-11 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档