依赖注入框架

在我们开发的过程中,我们会遇到一些依赖注入框架,所以总结一下:

Dagger2、koin、Hilt。其中现在用的多的是koin和Dagger2。但是由于Dagger2上手有难度,所以官方推出了Jetpack Hilt来代替Dagger2,所以现在主修koin和Hilt是可以的。

什么是依赖注入?为什么要依赖注入?

首先要明确什么是依赖?对Android而言,这只是一个名词,具体一点就是一个类的里面变量就是类的依赖,就称为类依赖于变量。所谓依赖注入就是内部的类的变量不由开发者来定义,而是由外部去引入注入。

依赖注入可以自动加载依赖,使用一个模块但不依赖这个模块的具体实现。并且实现了一个数据共享的一个机制。如果不需要共享的数据使用依赖注入可以使它更加的简洁,在加载的过程中可以免去初始化加载的过程,提高效率。

怎么进行依赖注入?

Hilt

Dagger2

Dagger2是一个依赖注入框架,官方维护的一个依赖注入框架。

https://github.com/google/dagger/releases

依赖注入是指所需要的事物是由注入来取代依赖。

在这里将依赖由注入传递给调用方。这里的依赖是一个变量,调用方是对象和类(PS:变量只是一个名称,对象是已经开辟了内存的地方。类似于人与人名的关系)

  1. 项目中多个模块会用到一些公共实例。
  2. 这些公共实例应该是单例对象。

其实我们所使用的依赖注入已经很多,类似于这样:

1
2
3
4
5
6
class edge{
Actionbar actionbar;
public edge(Actionbar actionbar){
this.actionbar=actionbar;
}
}

就是构造器来实现依赖注入,当调用构造函数的时候,就有一个对象被创造出来,将这个变量去注入了这个对象。

这是一个简单的依赖注入,我们还有setter方法,接口注入,依赖注入框架实现。

依赖注入的目的是为了解耦和便于维护,如果我使用依赖的方式来进行创建:

1
2
3
4
5
6
7
8
9
10
11
interface Energy {

}

class GasEnergy implements Energy {

}

class Car {
Energy energy = new GasEnergy();
}

类car会有多于的责任,负责这个energy对象的创建。如果我们想修改这个汽车的能源,那么必须修改这个汽车类。但是汽车使用哪种能源应该是由汽车制造商来决定,而不是由汽车决定。这就造成了耦合性高和维护不方便的麻烦。所以我们经常在多人协作项目的时候采用第三方的依赖注入框架,便于维护和解耦(控制反转的设计模式)

看了一篇博客中对依赖注入描述的一句话:Dependency injection (DI) is the concept in which objects get other required objects from outside.

  • 添加依赖(具体版本号见上述Github地址)
1
2
3
4
dependencies {
implementation 'com.google.dagger:dagger:2.x'
annotationProcessor 'com.google.dagger:dagger-compiler:2.x'
}
  • 使用注解(annotations)

    • @Moudle and @Provides:定义提供依赖的类和方法(Moudle注解在一个类上,Provides注解在一个方法上)
    • @Inject:使用在方法、构造器等请求依赖项的地方
    • @Component:执行依赖注入(通常在一个接口中使用)编译后会产生相应的Dagger类,这个类提供了依赖方和所需依赖方的桥梁。

    (注:dagger2不允许在私有域中使用)

  • 注入过程

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
        // Definition of the Application graph
    @Component
    public interface ApplicationComponent {
    }

    // appComponent lives in the Application class to share its lifecycle
    public class MyApplication extends Application {

    // Reference to the application graph that is used across the whole app
    ApplicationComponent appComponent = DaggerApplicationComponent.create();
    }

对于上述,只是去在类中注入一个依赖,所以可以直接利用create()来完成这个事情。

对于一个Activity就是利用Inject来注入。

@Inject 做的是将依赖对象注入到目标中,@Module 提供依赖对象(参数)。它们两个之间的联系谁来搭建呢? @Component就出现了

如果对于Activity来注入:

  1. 先找到需要注解的位置:
1
2
3
4
5
6
7
8
9
10
 public class MainActivity extends AppCompatActivity {
@Inject
MainPresenter mainPresenter;
...

@Override
protected void onCreate(Bundle savedInstanceState) {
...
}
}

这个注释是一定要在onCreate方法之前去注解@inject,因为在这个方法中会实现避免出现 Fragment 恢复问题。在 super.onCreate() 的恢复阶段,Activity 会附加可能需要访问 Activity 绑定的 Fragment。

在第一步结束以后,我们的MainActivity就持有了MainPresenter的引用,Mainpresenter被依赖。

  1. 为注入的实例化提供参数(@Module)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Module
public class MainModule {

private MainActivity mainActivity;

public MainModule(MainActivity activity){ mainActivity = activity;}

@Provides
public MainActivity providesActivity(){ return mainActivity; } //返回这个引用

@Provides
public User providesUser(){ return new User("the user from MainModule"); }//返回这个引用

@Provides
public MainPresenter providesMainPresenter(MainActivity activity,User user){
return new MainPresenter(activity,user);
}
}

返回值很重要,这样就说清楚了提供的参数

  1. 搭建桥梁(@Component)

这个Componet的作用就是告知Dagger需要注入依赖的对象,例如:

1
2
3
4
5
6
@Component
public interface ApplicationComponent {
// This tells Dagger that LoginActivity requests injection so the graph needs to
// satisfy all the dependencies of the fields that LoginActivity is injecting.
void inject(LoginActivity loginActivity);
}

注意:如果要注入的为两个参数,应该是两种inject方法而不是一种通用方法。

1
2
3
4
@Component(modules = MainModule.class)
public interface MainComponent {
void inject(MainActivity MainActivity);//参数要写成对应的activity
}

如果开发不同的Activity,那么我们就可以改变modules=… .class 和改变Inject的参数来进行改变。

做完了Component时,我们必须去ReBulid一下项目,这样才能生成我们需要的DaggerXXX类

4.编写注入代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class MainActivity extends AppCompatActivity {

@Inject
MainPresenter mainPresenter;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
//build代码开始
DaggerMainComponent.builder()
.mainModule(new MainModule(this))//DaggerMainComponent与MainActivityModule的实例绑定
//mainModule该方法名和MainModule是有关的,编译时生成
.build()
.inject(this);//该方法就是MainComponent接口的inject(),传入当前MainActivity的引用
//build代码结束
...

mainPresenter.showUserName();
}

参考