美文网首页
Dagger2最详细的使用教程和源码分析(一)基本注入使用

Dagger2最详细的使用教程和源码分析(一)基本注入使用

作者: 青墨一隅 | 来源:发表于2019-04-12 15:23 被阅读0次

    1.导入依赖

    implementation 'com.google.dagger:dagger:2.11'
    annotationProcessor 'com.google.dagger:dagger-compiler:2.11'
    

    最新版本请官网获取

    2.什么是Dagger2?

    • Dagger2一个谷歌开源的依赖注入(Dependency Injection)框架,简称DI。Dagger2 是 Google 出的依赖注入框架。肯定有小伙伴疑问,为什么会有个 2 呢。该框架是基于 Square 开发的 Dagger 基础上开发的。
    • Dagger2主要用于程序之间的解耦,程序的耦合性越低表明这个程序的可读性以及可维护性越高。控制反转(Inversion of Control或IOC)就是常用的面向对象编程的设计原则,使用这个原则我们可以降低耦合性。其中依赖注入是控制反转最常用的实现。

    3.为什么使用Dagger2?

    常用的依赖注入

    • 构造器注入
    public class A {
        private B b;
    
        A(B b) {
            this.b = b;
        }
    }
    
    • setter方法注入
    public class A {
        private B b;
    
        public void setB(B b) {
            this.b = b;
        }
    }
    
    • 接口注入
    //首先定义一个接口
    public interface IC {
        void printMess();
    }
    
    //A
    public class A implements IC {
    
        @Override
        public void printMess() {
            System.out.println("我的信息是A");
        }
    }
    
    //B
    public class B implements IC {
        @Override
        public void printMess() {
            System.out.println("我的信息是B");
        }
    }
    
    //D
    public class D {
        private IC ic;
    
        D(IC ic) {
            this.ic = ic;
            ic.printMess();
        }
    }
    
    /测试类
    public class Test {
        public static void main(String[] args) {
            new D(new A());
            new D(new B());
    
        }
    }
    

    输出结果:
    我的信息是A
    我的信息是B
    通过D类进行接口依赖注入,如果新增类去答应信息只需要在Test类中动态配置注入的参数就行。

    你肯定会说,这三种依赖注入的方式已经解决了程序解耦的问题,为什么还会出来一个Dagger2呢?那是因为上面3中依赖注入的方式都不能解决一个问题,那就是面对A、B类在程序中大量并且多个地方创建我们需要大量的new操作,如果这个时候有一个需求需要改变构造参数你该怎么办呢?全局搜索一个个去改?刚改完需求又变动怎么办?好吧我承认我受不了......
    那么我们的Dagger2就横空出世了,它通过java的注解的方式创建对象,省去new操作,在修改构造参数的时候只需要在一处修改即可,下面我们接着看如何实现。

    public class DaggerBean {
        private int age;
        private String name;
    
        @Inject
        public DaggerBean() {
            age = 17;
            name = "张三";
        }
    
        public int getAge() {
            return age;
        }
    
        public String getName() {
            return name;
        }
    }
    
    public class DaggerActivity extends AppCompatActivity {
        @Inject
        DaggerBean bean;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_dagger);
            initView();
        }
    
        private void initView() {
            TextView content = (TextView) findViewById(R.id.tv_dagger);
            content.setText(bean.getName()+"今年"+bean.getAge()+"岁了");
        }
    }
    

    直接运行程序会发生空指针异常,因为直接通过@Inject 注入DaggerBean对象是不会成功的,因为DaggerActivity不知道去哪里找到它的实例去注入生成,这时我们需要一个连接器Component,让上面这两个类产生联系:

    //创建一个Component
    /**
     * 1.必须是接口
     * 2.必须使用Component注解
     */
    @Component
    public interface DaggerComponent {
    
        /**
         * inject名称可以更改
         * @param daggerActivity 将Activity对象和DaggerBean进行关联的方法
         */
        void inject(DaggerActivity daggerActivity);
    }
    

    build一下项目(必须先build),然后我们修改一下DaggerActivity中的代码

    public class DaggerActivity extends AppCompatActivity {
        @Inject
        DaggerBean bean;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_dagger);
            initView();
        }
    
        private void initView() {
    
            //dagger2通过APT技术生成的类(后续我们会有专门的篇幅分析源码),进行注入
            DaggerDaggerComponent.builder()
                    .build()
                    .inject(this);
    
            TextView content = (TextView) findViewById(R.id.tv_dagger);
            content.setText(bean.getName() + "今年" + bean.getAge() + "岁了");
        }
    }
    

    运行结果


    image.png

    这一次运行成功了,是不是so easy!!!

    @Module

    尽管上面我们实现了操作但是同时我们也发现了一些问题:

    1. 在DaggerBean的构造函数需要使用@Inject进行注解,如果DaggerBean是系统类或者第三方库的类我们怎么办?
    2. 同时使用@Module和@Inject会以哪一个为主?
    3. 类的构造函数带有参数,直接使用@Inject会出现编译错误怎么办?

    为了解决上面的疑惑我们的下一个主角@Module闪亮登场,@Module和@Inject属于两个不同的纬度,我们先看第1个问题,首先先创建一个DaggerModule

    /**
     * 1.可以提供一些对象实例
     * 2.提供构造函数所需要的参数
     */
    @Module
    public class DaggerModule {
    
        /**
         * 必须使用Provides进行注解
         * @return 提供一个第三方库对象
         */
        @Provides
        public Gson provideGson(){
            return new Gson();
        }
    
    }
    

    修改一下DaggerActivity

    public class DaggerActivity extends AppCompatActivity {
        @Inject
        DaggerBean bean;
    
        @Inject
        Gson gson;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_dagger);
            initView();
        }
    
        private void initView() {
    
            //dagger2通过APT技术生成的类(后续我们会有专门的篇幅分析源码),进行注入
            DaggerDaggerComponnet.builder()
                    .build()
                    .inject(this);
    
            TextView content = (TextView) findViewById(R.id.tv_dagger);
            content.setText(gson.toJson(bean));
            //content.setText(bean.getName() + "今年" + bean.getAge() + "岁了");
        }
        
    }
    

    运行项目显示结果


    image.png

    接下来看第2个问题,首先修改DaggerBean

    public class DaggerBean {
        private int age;
        private String name;
    
        @Inject
        public DaggerBean() {
            age = 17;
            name = "张三";
        }
    
        public DaggerBean(int age,String name) {
            this.age = age;
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public String getName() {
            return name;
        }
    }
    

    修改

    
    /**
     * 1.可以提供一些对象实例
     * 2.提供构造函数所需要的参数
     */
    @Module
    public class DaggerModule {
    
        /**
         * 必须使用Provides进行注解
         * @return 提供一个第三方库对象
         */
        @Provides
        public Gson provideGson(){
            return new Gson();
        }
    
        @Provides
        public DaggerBean provideDaggerBean(){
            return new DaggerBean(20,"李四");
        }
    
    }
    

    运行项目


    image.png

    从运行结果可以看出来,module纬度的优先级更高一些。

    第三个问题特别需要注意一下,先看一下构造函数

        @Inject
        public DaggerBean(int age,String name) {
            this.age = age;
            this.name = name;
        }
    
    

    如果我们直接把代码写成这样去编译使通不过的,因为我们没有给构造函数传参数,并且构造函数中如果不能使用基本数据类型去传参,下面看一下如果我们想传递构造函数的参数如何来使用:
    新增一个类WrapDaggerData,进行包装数据

    public class WrapDaggerData {
        public int getAge(){
            return 22;
        }
    
        public String getName(){
            return "王五";
        }
    }
    
    //更改一下构造参数
    public class DaggerBean {
        private int age ;
        private String name ;
    
        @Inject
        public DaggerBean(WrapDaggerData wrapDaggerData) {
            age = wrapDaggerData.getAge();
            name = wrapDaggerData.getName();
        }
        
    }
    
    //修改一下
    @Module
    public class DaggerModule {
    
        /**
         * 必须使用Provides进行注解
         * @return 提供一个第三方库对象
         */
        @Provides
        public Gson provideGson(){
            return new Gson();
        }
    
        /**
         * 这里是提供构造参数的地方
         * @return
         */
        @Provides
        public WrapDaggerData provideDaggerGsonData(){
            return new WrapDaggerData();
        }
    
    }
    
    //修改一下
    @Component(modules = DaggerModule.class)
    public interface DaggerComponnet {
        void inject(DaggerActivity daggerActivity);
    
        /**
         *这里是重点,需要什么类型的构造参数需要在这里定义,方法名称没有特殊限制,这里是链接构造参数的桥梁
         * @return
         */
        WrapDaggerData getDaggerGsonData();
    }
    

    运行项目


    image.png

    从结果可以看出来构造函数的值传递成功。

    好了这篇文章就写到这里结束,这篇文章主要是介绍module和inject二种纬度的使用方法和区别以及构造函数如何传参的问题。

    如有写的不对的地方敬请留言告知!

    相关文章

      网友评论

          本文标题:Dagger2最详细的使用教程和源码分析(一)基本注入使用

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