Dagger2入门

    Dagger2是一个基于Java依赖注入的标准的依赖注入框架,他能够在编译器自动生成代码,负责依赖对象的创建。Dagger2是Dagger的升级版第一代由Square公司共享出来,第二代则是由谷歌接手开发出来,现在来学习它的使用方法。

    首先在gradle的dependencies中加入:

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

    在使用之前先来看一个例子。创建一个Worker类:

    public class Worker {

        public void work(){
            Log.e("TAG","工人干活");
        }
    }

    然后在Activity中使用:

    public class MainActivity extends AppCompatActivity {

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Worker worker = new Worker();
            worker.work();
        }
    }

    这样使用没有任何问题,但是MainActivity持有Worker的对象,这样解耦不彻底,那么现在就是要使用Dagger2进行彻底的解耦。

一、@Inject与@Component

1、改写Worker类:

    在Worker2的构造方法上面加上@Inject表明Dagger2可以使用Worker2的构造方法创建对象。

    public class Worker2 {

        @Inject
        public Worker2(){

        }
        public void work(){
            System.out.println("工人干活");
        }
    }

2、定义MainActivityComponent接口

    使用@Component来完成依赖注入,需要定义一个接口,接口名称一般为目标名称+Component,在编译后就会自动生成一个辅助类,他会把依赖的目标的实例注入到目标类中。这里定义的是MainActivityComponent,方法名称是inject,要注入的类是MainActivity,代码如下:

    @Component
    public interface MainActivityComponent {
        void inject(MainActivity activity);
    }

3、完成注入

    @Inject有两种注入方式,一个是成员变量注入,另一个是构造方法注入,在MainActivity中这两种方式都采用,如下:

    public class MainActivity extends AppCompatActivity {

        @Inject
        Worker2 mWorker2; //成员变量注入
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            DaggerMainActivityComponent.create().inject(this);  //构造方法注入
            mWorker2.work();
        }
    }

    @Inject 有两个作用:

  •      标记Worker2的构造方法,通知 Dagger2 在需要该类实例时可以通过该构造函数 new 出相关实例从而提供依赖。
  •      标记 MainActivity 的 Worker2 变量,通知 Dagger2 该变量实例需要由它来提供,也就是上述的需要Dagger2 去 new 出 Worker2 的实例 mWorker2 。

    @Component作用:

  •     是一个中间件去连接依赖提供方和依赖使用方。

二、@Module与@Provides

@Inject 标记构造方法来生成依赖对象的方式有它的局限性,如:

  • 接口(Interface),没有构造方法,自然无处标记。
  • 第三方库提供的类,不适合去直接修改源码,标记构造方法。

对于上述的问题,就需要 @Provide 来提供依赖。

1、编写Module类

    如果项目中使用的第三方库,这样使用就会报错,比如说Gson。这个时候就可以使用@Module与@Provides来处理。首先创建Module类:

    @Module
    public class GsonModule {

        @Provides
        public Gson provideGson() {

            return new Gson;
        }
    }

    将@Module标注在内类上,用来告诉Component,可以从这个类中获取依赖对象,也就是Gson类,将@Provides标注在方法上面表示可以通过这个方法进行获取Gson实例,两者都是一起使用的。需要注意的是:

  • @Provides 只能用于标记非构造方法,并且该方法必须在 @Moudle 内部。
  • @Provides 修饰的方法的方法名建议以 provide 开头。

2、定义MainActivityComponent接口

    @Component(modules = GsonModule.class)
    public interface MainActivityComponent2 {
        void inject(MainActivity activity);
    }

    这里和前面的而不一样的地方是modules = GsonModule.class,表示用来指定Module,需要注意的是可以指定多个Module。

3、完成注入

    public class MainActivity extends AppCompatActivity {

        @Inject
        Gson mGson;

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

            DaggerMainActivityComponent.create().inject(this);
            String jsonObj = "{'age': '32','name': '张三'}";
            Man man = mGson.fromJson(jsonObj, Man.class);
            Log.e("TAG",man.age);
            Log.e("TAG",man.name);
        }
    }

    如果使用的类是抽象的则@Inject无法使用,因为抽象类不能被实例化,此时也是需要使用@Module与@Provides。

三、@Named与@Qualifier

    @Qualifier是限定符,@Named是 @Qualifier的一种实现。当我们有两个依赖的时候,高层的Component就不知道我们使用的是哪个,例如新建抽象类Animals,实现类Dog,Cat,如下:

    public class AnimalsModule {

        @Provides
        public Animals provideDog(){
            return new Dog();
        }

        @Provides
        public Animals provideCat(){
            return new Cat();
        }
    }

    public class Zoo {
        private Animals mAnimals;

        @Inject
        public Zoo(Animals animals) {
            mAnimals = animals;
        }

        public void eatFood(){
            mAnimals.eat();
        }
    }

    public class MainActivity extends AppCompatActivity {
        @Inject
        Zoo mZoo;

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

    运行之后报错了,原因是我们提供了多个@Provides,Component不知道到底是用哪个,这个时候可以使用@Named,在AnimalsModule和Zoo的构造参数上面分别指明所需要的对象,假设使用猫,则需要Zoo的构造对象中指定@Named("Cat"),如下:

    @Module
    public class AnimalsModule {

        @Provides
        @Named("Dog")
        public Animals provideDog(){
            return new Dog();
        }

        @Provides
        @Named("Cat")
        public Animals provideCat(){
            return new Cat();
        }
    }

    public class Zoo {
        private Animals mAnimals;

        @Inject
        public Zoo(@Named("Cat") Animals animals) {
            mAnimals = animals;
        }

        public void eatFood(){
            mAnimals.eat();
        }
    }

四、@Singleton与@Scope

    @Scope是用来自定义注解的,而@Singleton是用来配合实现局部单例和全局单例的,需要要注意的是@Singlton本身不具备创建单例的能力为了实现全局单例这里使用@Scope和Application实现。

1、定义注解

    @ApplicationScope
    @Component(modules = GsonModule.class)
    public interface ActivityComponet {
        void inject(MainActivity mainActivity);
    }

2、定义Module

    @Module
    public class GsonModule {

        @ApplicationScope
        @Provides
        public Gson provideGson(){
            return new Gson();
        }
    }

3、定义MainActivityComponent

    @ApplicationScope
    @Component(modules = GsonModule.class)
    public interface MainActivityComponent {
        void inject(MainActivity activity);
    }

4、定义Application

    public class App extends Application {

        private static MainActivityComponent mActivityComponent;

        @Override
        public void onCreate() {
            super.onCreate();
            mActivityComponent = DaggerMainActivityComponent.builder().build();
        }

        public static MainActivityComponent getActivityComponet(){
            return mActivityComponent;
        }
    }

5、完成注入

    public class MainActivity extends AppCompatActivity {

        @Inject
        Gson mGson1;
        @Inject
        Gson mGson2;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            App.getActivityComponet().inject(this);
            Log.e("TAG",mGson1.toString());
            Log.e("TAG",mGson2.toString());
        }
    }
    看一下二者内存地址完全一致:


参考文献:https://segmentfault.com/a/1190000008677663#articleHeader7


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值