Android中的依赖项注入学习笔记

什么是依赖项注入

依赖项注入(DI)是一种广泛用于编程的技术,是一种对象接收其依赖的其他对象的技术,这些其他对象称为依赖项。类通常需要引用其他类,类可以通过以下三种方式获取所需的对象:
  1.直接在类构成其所需的依赖项。
  2.从其他地方抽取。
  3.以参数形式提供。应用可以在构造类时提供这些依赖项,或者将这些依赖传入需要各个依赖项的函数。
上面的三种方式中,第三种方式就是依赖项注入!使用这种方法,可以获取并提供类的依赖项,而不必让类实例自行获取。

在Android中有两种依赖项注入方法:

  • 构造函数注入。将某个类的依赖项传入其构造函数。
  • 字段注入(或setter注入)。

示例

以汽车和引擎为例,汽车需要依赖引擎才能发动,以下分别通过两种方式实现:非依赖注入和依赖注入。

非依赖注入的方式:
fun main(){
    val car = Car()
    car.start()

}
class Car(){
    private val mEgine=Engine()
    fun start(){
        mEgine.start()
    }
}
class Engine{
    fun start(){

    }
}
依赖注入的方式:

 构造函数注入


fun main(){
    val engine = Engine()
    val car = Car(engine)
    car.start()

}
class Car(val engine:Engine){
    fun start(){
        engine.start()
    }
}
class Engine{
    fun start(){

    }
}

 字段注入

fun main(){
    
    val car = Car()
    car.mEgine=Engine()
    car.start()

}
class Car(){
    lateinit var mEgine: Engine
    fun start(){
        mEgine.start()
    }
}
class Engine{
    fun start(){

    }
}

自动依赖项注入

程序员自行创建,提供并管理不同类的依赖项,而不依赖于库的依赖注入方式,称为手动依赖项注入或人工依赖项注入。随着依赖项和类增多,手动依赖项注入就越繁琐。手动依赖项注入还会带来多个问题:

  •   对于大型应用,获取所有依赖项并正确连接它们可能需要大量得样板代码。在多层架构中,要为顶层创建一个对象,必须提供其下层得所有依赖项。
  •  如果无法在传入依赖项之前构造依赖项,则需要编写并维护管理内存中依赖项生命周期得自定义容器。

解决这类问题得方法可以归为两类:

  •   基于反射得解决方案,可以在运行时连接依赖项代码。
  •   静态解决方案,可在编译时生成连接依赖项得代码。

Dagger是适用于Android的热门依赖库注入库,它提供了完全静态和编译时依赖项,解决了基于反射方案的开发和性能问题。

依赖项注入的优势

  • 重用类以及分离依赖项:更容易换掉依赖项的实现。由于控制反转,代码重用得以改进,并且类不再控制其他依赖项的创建方式,而是支持任何配置。
  • 易于重构:依赖项成为API Surface的可验证部分,因此可再创建对象时或编译时进行检查,而不时作为实现详情隐藏。
  • 易于测试:类不管理其依赖项,因此再测试时,你可以出传入不同的实现以测试所有不同用例。

Dagger在Android上的简单使用

添加依赖
    implementation 'com.google.dagger:dagger:2.4'
    annotationProcessor 'com.google.dagger:dagger-compiler:2.4'
Dagger的注解解析
  • @Inject: 有两个作用:一个是在需要依赖的类(目标类,即宿主)中标记成员变量告诉Dagger这个类型的变量需要一个实例对象。二是标记类中的构造方法(一般为无参构造方法)告诉Dagger我可以提供这种类型的依赖实例。
  • @Provides: 用来提供依赖实例,对方法进行注解,且都是有返回类型的。用来告诉Dagger,我们想如何创建并提供该类型的依赖实例(一般会在方法中new出实例)。用@Provides标记的方法,谷歌推荐采用provide是为前缀,必须用在@Module注解的类中,方法所需的参数也需要以方法的形式返回提供。
  • @Module: 用来标记类(一般类名以Module结尾)。Module主要的作用是用来集中管理@Provides标记的方法。我们定义一个被@Module注解的类,Dagger就会知道在哪里找到依赖来满足创建类的实例。modules的一个重要特征是被设计成区块并可以组合在一起供@Component所注解的类使用。
  • @Component:用来标记接口或者抽象类(一般以Component结尾),是@Inject(指第一个作用)和@Module之间的桥梁,主要职责是把二者组合在一起,Module中的实例对象必须在Component中暴露出来才能供之后使用。所有的components都可以通过它的modules知道它所提供的依赖范围。一个Component可以依赖一个或多个Component,并拿到被依赖Component暴露出来的实例,Component的dependencies属性就是确定依赖关系的实现。
  • @Scope:作用域,Dagger2通过自定义注解来限定作用域,有一个默认的作用域注解@Singleton,通常在Android中用来标记在App整个生命周期内存活的实例。也可以自定义一个@PerActivity、@PerFragment注解,用来表明实例生命周期与Activity、Fragment一致。我们可以自定义作用域的粒度(比如@PerUser等等)。
  • @Qualifier:限定符。当一个类的类型不足以标示一个依赖的时候,我们就可以用这个注解。
  • @SubComponent:如果我们需要父组件全部的提供对象,这时我们可以用包含方式而不是用依赖方式,相比于依赖方式,包含方式不需要父组件显式显露对象(依赖方式只能拿到暴露出的实例),就可以拿到父组件全部对象。且SubComponent只需要在父Component接口中声明就可以了。
基本的使用

1.通过@Inject、@Component实现依赖注入。

  • 定义一个需要依赖注入的对象

public class User {
    private  String name;


    @Inject
    public User(){
        this.name="Dagger";
    }

    public String getName() {
        return name;
    }
}


  • 定义一个Component

/**
 * 定义一个桥梁Component
 */
@Component
public interface MainComponent {
    /**
     *
     * 方法的参数传入需要注入的类名,不能是其父类。方法名可以自定义。
     * @param mainActivity
     */
    void inject(MainActivity mainActivity);
}

  • 提供一个宿主
public class MainActivity extends AppCompatActivity {

    //不能修饰private的变量
    @Inject
     public User user;

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

点击Make Project就会自动生成相应的代码。然后就可以通过生成的以Dagger为前缀的类,完成依赖对象的注入。

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

用@Inject存在些个缺点

  • @Inject注解的构造方法有参数的话,参数也需要有其他地方提供依赖
  • @Inject注解了一个对象的两个构造方法就会报错,dagger不知道用哪个进行实例化
  • 对于第三方库或者一些我们无法修改构造方法的对象无法使用@Inject

2.通过@Provides,@Module配合提供实例

  • User函数的修改

public class User {
    private  String name;

    //这里不再需要Inject
    public User(
            String name
    ){
        this.name=name;
    }

    public String getName() {
        return name;
    }
}

  • 创建一个Module来管理@Provides注解的方法
@Module
public class MainModule {

    @Provides
    public User provideUsr(){
        return new User("Dagger");
    }
}

  • Component的修改

/**
 * 定义一个桥梁Component
 */
@Component(modules = {MainModule.class})
public interface MainComponent {
    /**
     *
     * 方法的参数传入需要注入的类名,不能是其父类。方法名可以自定义。
     * @param mainActivity
     */
    void inject(MainActivity mainActivity);
}

Make Project的之后,就可以在目标类中初始化注入

public class MainActivity extends AppCompatActivity {
    @Inject
     public User user;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DaggerMainComponent.create().inject(this);
    }
}

以上是Dagger的简单使用,Dagger还有很多功能,需要后续去学习和完善。

参考链接:
https://blog.csdn.net/qq_24442769/article/details/79363231?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.control

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容