美文网首页
Android中的依赖项注入学习笔记

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

作者: 132xin | 来源:发表于2020-11-20 10:09 被阅读0次

    什么是依赖项注入

    依赖项注入(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

    相关文章

      网友评论

          本文标题:Android中的依赖项注入学习笔记

          本文链接:https://www.haomeiwen.com/subject/cdvkiktx.html