美文网首页
带你玩转Dagger2

带你玩转Dagger2

作者: Anwfly | 来源:发表于2020-02-29 21:46 被阅读0次

一.概述

  1. Dagger2是一个基于JSR-330标准的依赖注入框架,在编译期间自动生成代码,负责依赖对象的创建。
  • Java 依赖注入标准 JSR-330 简介概念
    JSR-330 是 Java 的依赖注入标准。定义了如下的术语描述依赖注入:
    A 类型依赖 B类型(或者说 B 被 A 依赖),则 A类型 称为”依赖(物) dependency”
    运行时查找依赖的过程,称为”解析 resolving“依赖
    如果找不到依赖的实例,称该依赖是”不能满足的 unsatisfied”
    在”依赖注入 dependency injection”机制中,提供依赖的工具称为”依赖注入器 dependency injector”
  1. 作用:管理对象及其生命周期
  2. 好处:统一管理对象,对象初始化一次即可,降低程序耦合。比如一个对象调用一千次,如果new的话需要一千次,现在只需要去找dagger2要即可,即使修改也就去找Dagger2修改一次即可。
  3. 使用场景:应用在比较复杂或者规模较大的App,简单App没必要大材小用。
  4. 介绍
    ①Module:提供对象的,注入到需要的地方。一个App中有很多module,比如httpObject、GlideObject等。
    ②Component:用于注入对象,从Module注入到需要的地方,比如controller等


    dagger2.png

二.具体使用

  1. 导入依赖
implementation 'com.google.dagger:dagger:2.17'
annotationProcessor 'com.google.dagger:dagger-compiler:2.17'
  1. 建包及使用(di:注入包、object:对象包)

①在object包创建对象类

public class HttpObject{
}

②在di包创建类HttpModule

/**
 * 提供Http对象
 *
 */
@Module
public class HttpModule {
    @Provides
    public HttpObject provodeHttpObject() {
        return new HttpObject();
    }
}

③在di包创建AnflyComponet接口用来注入对象

/**
 * 提供依赖注入的类
 */
@Component(modules = {HttpModule.class})
public interface AnflyComponet {
    /**
     * 提供注入方法,注意参数不能使用多态
     *
     * @param mainActivity
     */
    void injectMainactivty(MainActivity mainActivity);
}

④重新编译整个工程RebuildProject,生成DaggerAnflyComponet(实现原理是atp),在MainActivity中创建注入器并调用其方法,就可以通过@Inject注入HttpObject对象

public class MainActivity extends AppCompatActivity {

    @Inject
    HttpObject httpObject;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //生成DaggerAnflyComponet注解处理器
        DaggerAnflyComponet.create().injectMainactivty(this);

        Log.e("TAG", "httpObject=" + httpObject.hashCode());
    }
}

3.原理简介
刚才在MainActivity中使用DaggerAnflyComponet创建component,使用的使用create方式
①我们点击源码进去:

  public static AnflyComponet create() {
    return new Builder().build();
  }

②create最终使用的是构建者模式实现的,所以我们也可以直接在MainActivity中使用构建者模式创建注解处理器

AnflyComponet anflyComponet = DaggerAnflyComponet.builder()
                .httpModule(new HttpModule())
                .dataBaseModule(new DataBaseModule())
                .build();
        anflyComponet.injectMainactivty(this);

③点击.httpModule(new HttpModule())

public Builder httpModule(HttpModule httpModule) {
      this.httpModule = Preconditions.checkNotNull(httpModule);
      return this;
    }

通过构建者模式返回自身,当然这里做了非空判断:Preconditions.checkNotNull(httpModule)

ublic static <T> T checkNotNull(T reference) {
    if (reference == null) {
      throw new NullPointerException();
    }
    return reference;
  }

④点击build看看做了什么事情

 public AnflyComponet build() {
      if (httpModule == null) {
        this.httpModule = new HttpModule();
      }
      return new DaggerAnflyComponet(this);
    }

先判断httpModule 是否为空,如果为空就新建一个,最后返回DaggerAnflyComponet
至此,相当于把需要的对象在内存中生成。
⑤点击anflyComponet.injectMainactivty(this)跳转到我们自己写的接口方法


1582989016(1).png

该接口有自己的实现类,我们看看实现类

 @Override
  public void injectMainactivty(MainActivity mainActivity) {
    injectMainActivity(mainActivity);
  }

  private MainActivity injectMainActivity(MainActivity instance) {
    MainActivity_MembersInjector.injectHttpObject(
        instance, HttpModule_ProvodeHttpModuleFactory.proxyProvodeHttpModule(httpModule));
    return instance;
  }

通过MainActivity成员注射器 MainActivity_MembersInjector注入HttpObject

⑥声明HttpObject为单例

@Module
@Singleton
public class HttpModule {
    @Singleton
    @Provides
    public HttpObject provodeHttpModule() {
        return new HttpObject();
    }
}

@Singleton
@Component(modules = {HttpModule.class, DataBaseModule.class})
public interface AnflyComponet {
    /**
     * 提供注入方法,注意参数不能使用多态
     *
     * @param mainActivity
     */
    void injectMainactivty(MainActivity mainActivity);

    void injectSecondactivty(SecondActivity secondActivity);
}

现在新建一个SecondActivity同样打印HttpObject对象的hashcode,MainActivit打印两个HttpObject对象的hashcode。
MainActivit:

public class MainActivity extends AppCompatActivity {

    @Inject
    HttpObject httpObject;

    @Inject
    HttpObject httpObject2;

    private TextView tv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        //生成DaggerAnflyComponet注解处理器
        //第一中写法
        DaggerAnflyComponet.create().injectMainactivty(this);
        //第二种写法
        AnflyComponet anflyComponet = DaggerAnflyComponet.builder()
                .httpModule(new HttpModule())
                .dataBaseModule(new DataBaseModule())
                .build();
        anflyComponet.injectMainactivty(this);

        Log.e("TAG", "MainActivity httpObject=" + httpObject.hashCode());
        Log.e("TAG", "MainActivity httpObject2=" + httpObject2.hashCode());
    }

    private void initView() {
        tv = (TextView) findViewById(R.id.tv);
        tv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, SecondActivity.class);
                startActivity(intent);
            }
        });
    }
}

SecondActivity:

public class SecondActivity extends AppCompatActivity {

    @Inject
    HttpObject httpObject;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        DaggerAnflyComponet.create().injectSecondactivty(this);

        Log.e("TAG", "SecondActivity httpObject=" + httpObject.hashCode());
    }
}

结果是:

02-29 23:50:03.339 3667-3667/? E/TAG: MainActivity httpObject=745396538
02-29 23:50:03.339 3667-3667/? E/TAG: MainActivity httpObject2=745396538
02-29 23:50:05.176 3667-3667/com.anfly.dagger2 E/TAG: SecondActivity httpObject=951541497

结论:同一个activity中是同一个对象,但是不同activity中不是同一个对象,现在只达到了局部单例,但是项目中是需要全局单例的,怎么办呢??

⑦实现全局单例
方法:所有类使用同一个注射器,即在application中获取注射器,在不同类中去注入
创建一个application

public class DaggerApplication extends Application {

    private static DaggerApplication daggerApplication;
    private AnflyComponet anflyComponet;

    @Override
    public void onCreate() {
        super.onCreate();
        daggerApplication = this;

        anflyComponet = DaggerAnflyComponet.create();
    }

    public static DaggerApplication getDaggerApplication() {
        return daggerApplication;
    }

    public AnflyComponet getAnflyComponet() {
        return anflyComponet;
    }
}

在MainActivit中:

public class MainActivity extends AppCompatActivity {

    @Inject
    HttpObject httpObject;

    @Inject
    HttpObject httpObject2;

    private TextView tv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        //生成DaggerAnflyComponet注解处理器
        //第一中写法
//        DaggerAnflyComponet.create().injectMainactivty(this);
        //第二种写法
//        AnflyComponet anflyComponet = DaggerAnflyComponet.builder()
//                .httpModule(new HttpModule())
//                .dataBaseModule(new DataBaseModule())
//                .build();
//        anflyComponet.injectMainactivty(this);

        DaggerApplication.getDaggerApplication().getAnflyComponet().injectMainactivty(this);

        Log.e("TAG", "MainActivity httpObject=" + httpObject.hashCode());
        Log.e("TAG", "MainActivity httpObject2=" + httpObject2.hashCode());
    }

    private void initView() {
        tv = (TextView) findViewById(R.id.tv);
        tv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, SecondActivity.class);
                startActivity(intent);
            }
        });
    }
}

在SecondActivity中:

public class SecondActivity extends AppCompatActivity {

    @Inject
    HttpObject httpObject;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
//        DaggerAnflyComponet.create().injectSecondactivty(this);

        DaggerApplication.getDaggerApplication().getAnflyComponet().injectSecondactivty(this);
        Log.e("TAG", "SecondActivity httpObject=" + httpObject.hashCode());
    }
}

结果:

03-01 00:04:34.301 3817-3817/com.anfly.dagger2 E/TAG: MainActivity httpObject=745396538
03-01 00:04:34.301 3817-3817/com.anfly.dagger2 E/TAG: MainActivity httpObject2=745396538
03-01 00:04:36.139 3817-3817/com.anfly.dagger2 E/TAG: SecondActivity httpObject=745396538

结论:使用同一个注射器实现的全局单例

4.不同Component将对象同一个activity
不同的Component不能给同一个activity注入对象,实在想注入同一个activity只能想办法组装成一个component。
怎么组装呢?创建一个主component,其他次component可以通过dependencies = PresenterComponet.class添加到主component
①对象类

public class PresenterObject {
}

②提供对象的类

@Module
public class PresenterModule {
    @Provides
    public PresenterObject providePresenter() {
        return new PresenterObject();
    }
}

③注射器

@Component(modules = {PresenterModule.class})
public interface PresenterComponet {
    /**
     * 提供注入方法,注意参数不能使用多态
     *
     * 但是这里是从component,所以该方法不能用
     *
     * @param
     */
//    void injectMainactivty(MainActivity mainActivity);
//    void injectSecondactivty(SecondActivity secondActivity);

    public PresenterObject providePresenter();
}

这里需要注意的是,不需要在写一遍injectMainactivty(MainActivity mainActivity),因为在主component已经写过一遍了,只需要提供一个方法(来自module中方法);
④主component修改

@Singleton
@Component(modules = {HttpModule.class, DataBaseModule.class},
        dependencies = {PresenterComponet.class})
public interface AnflyComponet {
    /**
     * 提供注入方法,注意参数不能使用多态
     *
     * @param mainActivity
     */
    void injectMainactivty(MainActivity mainActivity);

    void injectSecondactivty(SecondActivity secondActivity);
}

第三行多了dependencies = {PresenterComponet.class},他表示这个主component引入了次component。
⑤RebuildProject
在DaggerApplication中添加一行:创建注入器

@Override
    public void onCreate() {
        super.onCreate();
        daggerApplication = this;

        anflyComponet = DaggerAnflyComponet.builder()
                .httpModule(new HttpModule())
                .presenterComponet(DaggerPresenterComponet.create())
                .build();
    }

现在就可以直接在MainActivity中直接调用presenterObject了。

  1. 将PresenterObject设置为单例。如果按照以前的写法,module和component添加注解@Singleton就会报错:
错误: [Dagger/IncompatiblyScopedBindings] com.anfly.dagger2.di.PresenterComponet (unscoped) may not reference scoped bindings:
@Provides @Singleton com.anfly.dagger2.object.PresenterObject com.anfly.dagger2.di.PresenterModule.providePresenter()

原因:使用dependencies的时候,多个组件之间的Scope不能相同,没有Scope的不能依赖有Scope的组件。
Scope是什么呢?用来标识组件,方便进行依赖关系绑定
解决方案:我们可以使用scope替换掉所用的@Singleton就能解决问题了
①创建一个scope文件,再创建一个APPScope类,这个代码是@Singleton源码

@Scope
@Documented
@Retention(RUNTIME)
public @interface AppScope {
}

首先直接将主component相关的@Singleton替换为@AppScope

@Module
public class HttpModule {
    @AppScope
    @Provides
    public HttpObject provideHttpModule() {
        return new HttpObject();
    }
}

@AppScope
@Component(modules = {HttpModule.class, DataBaseModule.class},
        dependencies = {PresenterComponet.class})
public interface AnflyComponet {
    /**
     * 提供注入方法,注意参数不能使用多态
     *
     * @param mainActivity
     */
    void injectMainactivty(MainActivity mainActivity);

    void injectSecondactivty(SecondActivity secondActivity);
}

每一个组件或者component对应一个Scope,为presenter创建一个scope

@Scope
@Documented
@Retention(RUNTIME)
public @interface PresenterSingleScope {
}

然后

@PresenterSingleScope
@Component(modules = {PresenterModule.class})
public interface PresenterComponet {
    /**
     * 提供注入方法,注意参数不能使用多态
     *
     * 但是这里是从component,所以该方法不能用
     *
     * @param
     */
//    void injectMainactivty(MainActivity mainActivity);
//    void injectSecondactivty(SecondActivity secondActivity);

    public PresenterObject providePresenter();
}

@Module
public class PresenterModule {
    @PresenterSingleScope
    @Provides
    public PresenterObject providePresenter() {
        return new PresenterObject();
    }
}

打印结果:

03-01 04:03:18.332 5482-5482/com.anfly.dagger2 E/TAG: MainActivity httpObject=745396538
03-01 04:03:18.332 5482-5482/com.anfly.dagger2 E/TAG: MainActivity httpObject2=745396538
03-01 04:03:18.332 5482-5482/com.anfly.dagger2 E/TAG: MainActivity presenterObject=533813739
03-01 04:03:21.948 5482-5482/com.anfly.dagger2 E/TAG: SecondActivity httpObject=745396538
03-01 04:03:21.948 5482-5482/com.anfly.dagger2 E/TAG: SecondActivity presenterObject=533813739

结论:我们实现了多个组件或者component向同一个activity注入对象,并且实现全局单例。

三.高级用法
出来混迟早要还的,技术债Dagger2:Android篇
可能是东半球最好的dagger2文章
浅析Dagger2的使用

相关文章

网友评论

      本文标题:带你玩转Dagger2

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