美文网首页
Android Dagger2简单使用

Android Dagger2简单使用

作者: BlueSocks | 来源:发表于2023-12-07 17:53 被阅读0次

    Dagger是一个很古老的框架了,当初诞生时候,主要是为了模块之间的解耦。本篇文章主要介绍一下如何使用dagger2,后续会介绍其原理。

    AS集成

    对于现在的AS项目,一般都是会集成Kotlin和Java混写,所以可以在想要使用dagger的模块module的gradle下加入如下配置。

    implementation 'com.google.dagger:dagger:2.21'
    kapt 'com.google.dagger:dagger-compiler:2.21'
    
    

    注意这里用到了kapt,这就要求我们对应module的gradle顶部有如下配置:

        apply plugin: 'kotlin-kapt'
    
    

    如何使用

    假设我们现在存在一个类TestA, 结构如下:

        public class TestA {
    
            private int count = 0;
            
            public String getValue() {
                return "123321";
            }
            
            public int addSelf(){
                return ++count;
            }
        }
    
    

    我们现在呢,要在TestB中使用到TestA的对象实例,常规写法呢,就是new一个对象进行方法调用:

    • 常规写法
        public class TestB {
    
            private final TestA testA = new TestA();
    
            public void show() {
                for (int i = 0; i < 2; i++) {
                    testA.addSelf();
                    System.out.println(testA.getValue());
                }
            }
        }
    
    
    • 使用dagger

    常规写法要求我们对于一个对象必须要实例化,才能使用。那么在项目比较大型的时候,如果很多地方都用到了该对象,且进行了实例化。那么后续只要对象构造器里增加一个入参,那么就需要修改所有地方。

    这样很容易出错,dagger这个时候就可以起作用了,dagger可以帮我们自动去书写实例化对象的代码,而我们只需要关注使用testA对象即可。

    让我们看下使用dagger,这里代码怎么写。

        public class TestB {
    
            @Inject
            TestA testA;
    
            public void show() {
                for (int i = 0; i < 2; i++) {
                    testA.addSelf();
                    System.out.println(testA.getValue());
                }
            }
        }
    
    

    可以看到,区别就是将new TestA去掉了,加上了@Inject注解,让Dagger自动帮我们去进行TestA的实例化,我们只需要加上注解后,在下方直接使用其方法即可。

    现在我们知道了dagger的作用和简单的使用场景,我们来看下如果要实现上述例子中TestA这种直接加注解来实例对象的方式,该怎么操作。

    使用dagger来实现TestA自动实例化

    下图是Dagger里最基本的几个注解的使用及关系。


    image.png

    对于上述TestA的例子。我们首先按照上图所示,定义一个Module,如下:

        @Module
        public class TestAModule {
    
            @Provides
            public TestA provide() {
                return new TestA();
            }
        }
    
    

    这里对于provide方法可以任意命名,只要返回值是TestA就可以。同时TestAModule也可以任意命名,只要加上Module注解即可。

    接着,我们定义桥梁Component,类和方法也可以随意命名。

        @Component(modules = TestAModule.class)
        public interface TestAComponent {
    
            void injectIntoTestB(TestB testB);
        }
    
    

    注意Component上要写上,该Component所对应的Module,以便Dagger可以关联两者。同时内部定义一个接口也需要传入TestB对象,以便告诉Dagger,我们想要在哪个类中使用TestA实例。

    做完这些,最后一步就是在TestB中使用了。

        public class TestB {
    
            @Inject
            TestA testA;
    
            public void show() {
                for (int i = 0; i < 2; i++) {
                    testA.addSelf();
                    System.out.println(testA.getValue());
                }
            }
        }
    
    

    注意这里TestA不可以是private修饰。

    我们需要先build一下,编译完成后,还需要最后一步,在TestB中运行一下Dagger。可以在show方法中加上如下方法:

    DaggerTestAComponent.create().injectIntoTestB(this);
    
    
    

    DaggerTestAComponent是Dagger在我们构建编译时候为我们生成的,所以此时不编译是看不到这个类的,必须编译一下。

    运行一下,我们就可以使用这个类了。所有Dagger自动生成的类都是以Dagger开头。

    如果找不到文件!!\color{red}{如果找不到文件!!}如果找不到文件!!

    可能某些小伙伴发现,编译后仍然找不到这个类,那么说明你的项目开启了增量编译,需要gradle.properties中将其关闭。     在 gradle.properties 中加上如下配置,然后删除build文件夹,重新编译。

    kapt.incremental.apt = false
    
    

    最后我们运行一下,发现日志可以成功打印,说明执行成功了。

    注意这个时候,TestB文件中张这样。

    public class TestB {
    
        @Inject
        TestA testA;
    
        public void show() {
            DaggerTestAComponent.create().injectIntoTestB(this);
            for (int i = 0; i < 2; i++) {
                testA.addSelf();
                System.out.println(testA.getValue());
            }
        }
    
    

    实现单例

    上述我们简单实现了个例子,同时我们可以在类中直接实例化一个对象并进行使用。我们看下如何实现。

    我们可以在Provides注解标注的方法上加上Singleton注解,表示通过该方法生成的对象为单例对象,但是要注意,该单例的范围仅限于inject时候传入的对象。

    比如:

    @Module
    public class TestAModule {
    
        @Provides
        @Singleton
        public TestA provide() {
            return new TestA();
        }
    }
    
    

    注意在Component上也要加上Singleton注解。

    @Component(modules = TestAModule.class)
    @Singleton
    public interface TestAComponent {
    
        void injectIntoTestB(TestB testB);
    
        void injectIntoTestC(TestC testC);
    }
    
    

    对于上述方法,我在TestB和TestC中使用时候:

    public class TestB {
    
        @Inject
        TestA testA1;
    
        @Inject
        TestA testA2;
    
        public void show() {
            DaggerTestAComponent.create().injectIntoTestB(this);
            System.out.println(testA1);
            System.out.println(testA2);
        }
    }
    
    public class TestC {
    
        @Inject
        TestA testA1;
        
        @Inject
        TestA testA2;
    
        public void dd() {
            DaggerTestAComponent.create().injectIntoTestC(this);
            System.out.println("C:" + testA1);
            System.out.println("C:" + testA2);
        }
    }
    
    

    我们同时运行dd和show方法时候,会发现两个dd方法内地址打印一样,show方法内地址打印一样,但是dd方法和show方法打印的地址就不一样了。这是因为单例的范围和inject传入的对象有关,只在传入的对象范围内生效。

    name标签

    Dagger存在一个Name标签,主要用于确定对象的不同生成方式。比如我们TestA存在多个构造器。

    public class TestA {
    
        public TestA() {
        }
    
        public TestA(int count) {
            this.count = count;
        }
    
        private int count = 0;
    
        public String getValue() {
            return "123321 " + count;
        }
    
    

    那么可以在module中使用name来区分不同方式来生成对象实例。

    @Module
    public class TestAModule {
        @Provides
        @Named("11")
        public TestA provide() {
            return new TestA();
        }
    
        @Provides
        @Named("22")
        public TestA provide2() {
            return new TestA(22);
        }
    
    

    我们在TestB中使用,

    public class TestB {
    
        @Inject
        @Named("11")
        TestA testA1;
    
        @Inject
        @Named("22")
        TestA testA2;
    
        public void show() {
            DaggerTestAComponent.create().injectIntoTestB(this);
            System.out.println("11=>" + testA1.getValue());
            System.out.println("22=>" + testA2.getValue());
        }
    
    

    运行一下方法 show,可以看到此时testA1和testA2分别调用了不同的构造器生成了对象。

    总结

    个人感觉,dagger在当下直接使用,比较鸡肋,想不到很合适的使用场景,毕竟当下这么多框架和新技术,对于各种场景,完全有更合适的框架。所以本文只打算对dagger研究这么多。为后续Hilt学习打个基础吧。

    相关文章

      网友评论

          本文标题:Android Dagger2简单使用

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