Dagger2使用方法及源码解析(一)

Dagger2使用方法及源码解析

1.Dagger2简介

2.Dagger2项目依赖

3.Dagger2基础使用方法

4.Dagger2使用方法拓展

5.Dagger2基础源码分析

.
.
.

1.Dagger2简介 :

Dagger是一种对Java和Android的静态的,编译时依赖注入(Dependency Injection)框架。它主要用来解决很多由于大量使用反射reflection而带来的开发和性能问题。总而言之,Dagger是一套依赖注入的框架,不懂依赖注入的朋友请自行学习。
这里推荐一篇大神的文章:轻松学,浅析依赖倒置(DIP)、控制反转(IOC)和依赖注入(DI)
.
.

2.Dagger2项目依赖

  //dagger2相关
    implementation 'com.google.dagger:dagger:2.4'
    annotationProcessor 'com.google.dagger:dagger-compiler:2.4'

.
.
3.Dagger2基础使用方法

现在我们假设有这样三个类:1.苹果,2.香蕉,3.小刀
小刀可以削苹果,也可以切开香蕉,但我们在使用小刀的时候需要有一个苹果或者香蕉来让我们切一下,所以我们就需要依赖于香蕉和苹果的对象。
在一般未使用Dagger的情况下,我们的代码是这个样子的:

public class Knife
{
    private static final String TAG = "aaa";
    private Apple apple;
    private Bnana bnana;
    
    public void cut()
    {
        apple = new Apple();
        bnana = new Bnana();
        Log.d(TAG, "cut: 我要切苹果");
        apple.introSelf();
        Log.d(TAG, "cut: 我要切香蕉");
        apple.introSelf();
    }
}

其中Apple类和Bnana类的代码如下:

public class Apple
{
    private static final String TAG = "aaa";

    public void introSelf()
    {
        Log.d(TAG, "555,我是苹果");
    }
}
public class Bnana
{
    private static final String TAG = "aaa";

    public void introSelf()
    {
        Log.d(TAG, "我是香蕉");
    }
}

当我们使用依赖注入时(未使用Dagger),Knife类的代码变成了这样

public class Knife
{
    private static final String TAG = "CUT";
    
    public void cut(Apple apple, Bnana bnana)
    {
        Log.d(TAG, "cut: 我要切苹果");
        apple.introSelf();
        Log.d(TAG, "cut: 我要切香蕉");
        apple.introSelf();
    }
}

是不是对于Knife对象来说,工作变得更简单了,而且降低了这三个类之间的耦合性。但对于我们coder来说,我们仍然需要new出一个Apple对象和一个Bnana对象,然后传入cut()方法中,工作量并没有显著的减少。
然而,当我们使用dagger时,Knife类的代码有了如下的变化:

public class Knife
{
    private static final String TAG = "CUT";

    @Inject
    Apple apple;
    
    @Inject
    Bnana bnana;
    
  	@Inject
    public Knife() {
    }
 
    public void cut()
    {
        Log.d(TAG, "cut: 我要切苹果");
        apple.introSelf();
        Log.d(TAG, "cut: 我要切香蕉");
        apple.introSelf();
    }
}

我们不再需要关心在哪new出这两个对象,只要使用注解标注我们需要注入的对象即可。
下面我们来看看Dagger2中常见的几种注解:

@Inject注解

上面你的代码中我们用了 @Inject 注解,它可以为我们自动注入对Apple对象和Bnana对象的依赖。但这样做的前提是我们的Apple类或者Bnana类的构造函数中需要使用 @Inject 注解来标记。
Apple类现在的代码如下:

public class Apple
{
    private static final String TAG = "aaa";

    @Inject
    public Apple() {
    }

    public void introSelf()
    {
        Log.d(TAG, "555,我是苹果");
    }
}

这样我们Knife类中的Apple对象便由Dagger2自动为我们注入了,我们在代码中并没有主动的去new一个Apple对象。一切交由Dagger2框架自动完成。

.
.
.
另外一个场景:
现在我们想切一个香蕉吃,但我们手头并没有香蕉,香蕉都生长的热带地区,香蕉不会自己长腿跑到我们手里。此时我们只能通过中间商–水果店来获得香蕉。此时水果店就变成了一个Module

@Module注解

在我们使用第三方文件时,并不被允许更改其类内的文件(让我们在其构造函数上加上@inject注解),此时我们就需要一个中间类来帮我们获取第三方的对象。简单点如下:

@Module
public class DaggerModule {

    @Provides
    public Bnana getBnana()
    {
    //简单写法,一般会视情况传入一个接口或者父类
        return new Bnana();
    }
}

@Provides注解

配合 @Module注解 来使用,表示通过这个方法获取对象实例

@Component

现在我们主要的代码已经差不多了,但我们可以发现我们所有的类都是单独的,只用@inject注解去标记依赖,此时我们需要一个桥梁------一个被 @Component 注解的接口,来将两个对应类型的 @inject 注解联系起来,并且决定是使用 @inject注解标记构造函数的形式来注入依赖,还是使用 @Module 注解和 @Provides 注解来注入依赖。

其实它的规则是当它持有的类的实例中出现 @Inject 注解时(如上面的例子中MainActivity中出现了被@Inject注解的Knife对象),优先扫描 @Module 注解和 @Provides 注解来注入依赖,然后才是扫描该对象的构造函数,查看其是否也使用了 @Inject 注解。

在我们的ManiActivity,我们需要获得Knife对象,所以我们将ManiActivity对象的实例写入 @Component注解的接口中,让dagger为我们注入MainActivity所需的依赖。其中modules可以为多个值,以modules = {Module1.class,Module2.class}的形式写入。在这里虽然我们的MainActivity没有用到Bnana对象(使用Module和provider),但是我们用到了Knife对象,Knife对象需要对Bnana对象的依赖(这里是一个嵌套依赖)。DaggerModule这个类代码如下:

//modules = 自己定义的可以提供目标对象的module类
@Component(modules = {DaggerModule.class})
public interface MainActivityComponent
{
    //为传入的MainActivity对象注入所需的依赖knife,并且为knife注入所需要的的依赖
    void inject(MainActivity mainActivity);
}

我们的MainActivity的代码如下:
为了对比两种注入方法,我们将切苹果和切香蕉分开写。

public class MainActivity extends AppCompatActivity {
    Button apple;
    Button bnana;

    @Inject
    Knife knife;

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

//核心代码
        MainActivityComponent component = DaggerMainActivityComponent.builder().build();
        component.inject(this);

    }

    private void initOnclike() {
        apple.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                knife.cutApple();

            }
        });
        bnana.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                knife.cutBnana();
            }
        });

    }

    private void initView() {
        apple = findViewById(R.id.eatApple);
        bnana = findViewById(R.id.eatBnana);

    }
}

到这里,Dagger的简单使用demo就好了,梳理一下依赖注入的两种基本手段:

1.在需要依赖的类中使用 @Inject 注解一个需要被注入的类的对象,然后在该类中使用 @Inject 注解该类的无参构造函数。
2.在Module中提供一个使用 @provider注解一个能返回目标对象的方法,在这里又分两种情况,一种是是这个对象是在参数中传进来的(情况1),另外一种是new一个对象返回的(情况2)。两种方法的区别是当该类的构造方法可以被@injectz注解时,使用第一种或者第二种都可以,但反之只能使用第一种。

情况1:
	 @Provides
     public Bnana getBnana(Bnana bnana)
    {
        return  bnana;
    }
情况2:

	@Provides
     public Bnana getBnana()
    {
        return  new GuaZi();
    }

为避免文章篇幅过长,剩下的内容将在下篇文章中涉及。Dagger2使用方法及源码解析(二)

发布了47 篇原创文章 · 获赞 15 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_41525021/article/details/103457063
今日推荐