Dagger 2 完全解析(三),Component 的组织关系与 SubComponent

dagger-lazy-cycle:dagger2 中使用 Lazy 支持循环依赖的提案 匕首懒惰循环 dagger2 中使用Lazy或Provider支持循环依赖的建议 Dagger 2.0 目前不支持任何类型的依赖循环。 Dagger 1 允许使用Lazy<T>或Provider<T>依赖包装器。 这里开始了一个问题: : 我已经开始使用在上述问题中发现的示例代码来展示问题。 我复制了 dagger 生成的代码,检查了生成的代码并对其进行了更改,并找到了一种在生成的代码中使用Lazy启用依赖项循环的方法。 基本上Provider<Lazy>>被传递给Bar_MembersInjector而不是Provider<Foo> 。 当Bar.lazyFoo.get()时,组件的fooProvider已初始化。 主要变化可以在这个提交中看到: : 类似的方法可能可用于Provider<T>依赖项。 立即下载

Dagger 2 完全解析系列:

Dagger 2 完全解析(一),Dagger 2 的基本使用与原理

Dagger 2 完全解析(二),进阶使用 Lazy、Qualifier、Scope 等

Dagger 2 完全解析(三),Component 的组织关系与 SubComponent

Dagger 2 完全解析(四),Android 中使用 Dagger 2

Dagger 2 完全解析(五),Kotlin 中使用 Dagger 2

Dagger 2 完全解析(六),dagger.android 扩展库的使用

上面文章地址是我博客上的地址,本系列文章是基于 Google Dagger 2.11-rc2 版本

在上篇文章中介绍了 Dagger 2 的三个核心要素,但是在实际使用过程中,还需要 Layz 注入、Qualifier(限定符)、Scope(作用域)等作为补充,也是在 Dagger 2 进阶中必须要掌握的内容。下面由简入繁地讲解这几个概念,同时结合 Dagger 2 的编译时生成代码分析背后的原理(示例代码沿用第一篇的,建议先阅读第一篇)。

在分析 Qualifier(限定符)、Scope(作用域)之前,先介绍一些简单的概念: Lazy 和 Provider 注入。

Lazy (延迟注入)

有时我们想注入的依赖在使用时再完成初始化,加快加载速度,就可以使用注入Lazy<T>。只有在调用 Lazy<T> 的 get() 方法时才会初始化依赖实例注入依赖。

public class Man {
    @Inject
    Lazy<Car> lazyCar;

    public void goWork() {
        ...
        lazyCar.get().go(); // lazyCar.get() 返回 Car 实例
        ...
    }
}

Provider 注入

有时候不仅仅是注入单个实例,我们需要多个实例,这时可以使用注入Provider<T>,每次调用它的 get() 方法都会调用到 @Inject 构造函数创建新实例或者 Module 的 provide 方法返回实例。

public class CarFactory {
    @Inject
    Provider<Car> carProvider;

    public List<Car> makeCar(int num) {
        ...
        List<Car> carList = new ArrayList<Car>(num);
        for (int i = 0; i < num; i ++) {
            carList.add(carProvider.get());
        }
        return carList;
    }
}

Qualifier(限定符)

试想这样一种情况:沿用之前的 Man 和 Car 的例子,如果 CarModule 提供了两个生成 Car 实例的 provide 方法,Dagger 2 在注入 Car 实例到 Man 中时应该选择哪一个方法呢?

@Module
public class CarModule {
    @Provides
    static Car provideCar1() {
        return new Car1();
    }
    @Provides
    static Car provideCar2() {
        return new Car2();
    }
    // Car1 和 Car2 是 Car 的两个子类
}

这时 Dagger 2 不知道使用provideCar1还是provideCar2提供的实例,在编译时就会报错,这种情况也可以叫依赖迷失(网上看到的叫法)。而@Qualifier注解就是用来解决这个问题,使用注解来确定使用哪种 provide 方法。

下面是自定义的@Named注解,你也可以用自定义的其他 Qualifier 注解:

@Qualifier
@Documented
@Retention(RUNTIME)
public @interface Named {
  String value() default "";
}

在 provide 方法上加上@Named注解,用来区分

@Module
public class CarModule {
    @Provides
    @Named("car1")
    static Car provideCar1() {
        return new Car1();
    }
    @Provides
    @Named("car2")
    static Car provideCar2() {
        return new Car2();
    }
}

还需要在 Inject 注入的地方加上@Named注解,表明需要注入的是哪一种 Car:

public class Man {
    @Inject
    @Named("car1")
    Car car;
    ...
}

这样在依赖注入时,Dagger 2 就会使用provideCar1方法提供的实例,所以Qualifier(限定符)的作用相当于起了个区分的别名。

Scope(作用域)

Scope 是用来确定注入的实例的生命周期的,如果没有使用 Scope 注解,Component 每次调用 Module 中的 provide 方法或 Inject 构造函数生成的工厂时都会创建一个新的实例,而使用 Scope 后可以复用之前的依赖实例。下面先介绍 Scope 的基本概念与原理,再分析 Singleton、Reusable 等作用域。

Scope 基本概念

先介绍 Scope 的用法,@Scope是元注解,是用来标注自定义注解的,如下:

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

MyScope 就是一个 Scope 注解,Scope 注解只能标注目标类、@provide 方法和 Component。Scope 注解要生效的话,需要同时标注在 Component 和提供依赖实例的 Module 或目标类上。Module 中 provide 方法中的 Scope 注解必须和 与之绑定的 Component 的 Scope 注解一样,否则作用域不同会导致编译时会报错。例如,CarModule 中 provide 方法的 Scope 是MyScope 的话,ManComponent 的 Scope 必须是 是 MyScope 这样作用域才会生效,而且不能是@Singleton或其他 Scope 注解,不然编译时 Dagger 2 会报错(亲自测试过)。

那么 Scope 注解又是如何产生作用的呢,怎么保证生成的依赖实例的生命周期呢?

在 Dagger 2 官方文档中我找到一句话,非常清楚地描述了@Scope的原理:

When a binding uses a scope annotation, that means that the component object holds a reference to the bound object until the component object itself is garbage-collected.

当 Component 与 Module、目标类(需要被注入依赖)使用 Scope 注解绑定时,意味着 Component 对象持有绑定的依赖实例的一个引用直到 Component 对象本身被回收。也就是作用域的原理,其实是让生成的依赖实例的生命周期与 Component 绑定,Scope 注解并不能保证生命周期,要想保证赖实例的生命周期,需要确保 Component 的生命周期。

下面以@MyScope为例,看 Scope 注解背后的代码:

@Module
public class CarModule {

    @Provides
    @MyScope
    static Car provideCar() {
        return new Car();
    }
}
@MyScope
@Component(modules = CarModule.class)
public interface ManComponent {
    void injectMan(Man man);
}

这样生成的 Car 实例就与 ManComponent 绑定了。下面看编译时生成的代码:

public final class DaggerManComponent implements ManComponent {
  private Provider<Car> provideCarProvider;
  private MembersInjector<Man> manMembersInjector;
...
  @SuppressWarnings("unchecked")
  private void initialize(final Builder builder) {

    this.provideCarProvider = DoubleCheck.provider(CarModule_ProvideCarFactory.create());

    this.manMembersInjector = Man_MembersInjector.create(provideCarProvider);
  }
...
}

public final class DoubleCheck<T> implements Provider<T>, Lazy<T> {
  private static final Object UNINITIALIZED = new Object();

  private volatile Provider<T> provider;
  private volatile Object instance = UNINITIALIZED; // instance 就是依赖实例的引用
...
  @SuppressWarnings("unchecked") // cast only happens when result comes from the provider
  @Override
  public T get() {
    Object result = instance;
    if (result == UNINITIALIZED) {  // 只生成一次实例,之后调用的话直接复用
      synchronized (this) {
        result = instance;
        if (result == UNINITIALIZED) {
          result = provider.get();  // 生成实例
          /* Get the current instance and test to see if the call to provider.get() has resulted
           * in a recursive call.  If it returns the same instance, we'll allow it, but if the
           * instances differ, throw. */
          Object currentInstance = instance;
          if (currentInstance != UNINITIALIZED && currentInstance != result) {
            throw new IllegalStateException("Scoped provider was invoked recursively returning "
                + "different results: " + currentInstance + " & " + result + ". This is likely "
                + "due to a circular dependency.");
          }
          instance = result;
          /* Null out the reference to the provider. We are never going to need it again, so we
           * can make it eligible for GC. */
          provider = null;
        }
      }
    }
    return (T) result;
  }
...
}

从上面 DaggerManComponent 的代码可以看出使用了 MyScope 作用域后,provideCarProvider由CarModule_ProvideCarFactory.create()变为了DoubleCheck.provider(CarModule_ProvideCarFactory.create())。而 DoubleCheck 包装的意义在于持有了 Car 的实例,而且只会生成一次实例,也就是说:没有用 MyScope 作用域之前,DaggerManComponent 每次注入依赖都会新建一个 Car 实例,而用 MyScope 作用之后,每次注入依赖都只会返回第一次生成的实例。DaggerManComponent 持有 provideCarProvider 引用,provideCarProvider 又持有 instance(即 Car 实例)的引用,所以生成 Car 对象实例的生命周期就和 Component 一致了,作用域就生效了。

Scope 作用域的本质:Component 间接持有依赖实例的引用,把实例的作用域与 Component 绑定,它们不是同年同月同日生,但是同年同月死。

Singleton Scope

在了解作用域的原理后,再来理解 Dagger 2 提供的自带作用域就容易了。@Singleton顾名思义保证单例,那么它又是如何实现的呢,实现了单例模式那样只返回一个实例吗?

把上面例子中@MyScope换成@Singleton,发现生成的 DaggerManComponent 和其他类没有变化。也只是用DoubleCheck包装了工厂而已,并没有什么特殊实现。所以 Singleton 作用域可以保证一个 Component 中的单例,但是如果产生多个 Component 实例,那么实例的单例就无法保证了。

所以在网上一些例子中,有看到AppComponent使用 Singleton 作用域,保证绑定的依赖实例的单例。它生效的原因是AppComponent只会在 Application 中创建一次,由AppComponent的单例来保证绑定的依赖实例的单例。

注意:Component 可以同时被多个 Scope 标记。即 Component 可以和多个 Scope 的 Moudle 或目标类绑定。

Reusable Scope

上文中的自定义的@MyScope和@Singleton都可以使得绑定的 Component 缓存依赖的实例,但是与之绑定 Component 必须有相同的 Scope 标记。假如我只想单纯缓存依赖的实例,可以复用之前的实例,不想关心与之绑定是什么 Component,应该怎么办呢?。

这时就可以使用@Reusable作用域,Reusable 作用域不关心绑定的 Component,Reusable 作用域只需要标记目标类或 provide 方法,不用标记 Component。下面先看看使用 Reusable 作用域后,生成的 DaggerManComponent 的变化:

public final class DaggerManComponent implements ManComponent {
...
  @SuppressWarnings("unchecked")
  private void initialize(final Builder builder) {
    this.provideCarProvider = SingleCheck.provider(CarModule_ProvideCarFactory.create()); // DaggerManComponent 的改动

    this.manMembersInjector = Man_MembersInjector.create(provideCarProvider);
  }
...
}

public final class SingleCheck<T> implements Provider<T>, Lazy<T> {
  private static final Object UNINITIALIZED = new Object();

  private volatile Provider<T> provider;
  private volatile Object instance = UNINITIALIZED; // 缓存实例的引用
...
  @SuppressWarnings("unchecked") // cast only happens when result comes from the delegate provider
  @Override
  public T get() {
    // provider is volatile and might become null after the check to instance == UNINITIALIZED, so
    // retrieve the provider first, which should not be null if instance is UNINITIALIZED.
    // This relies upon instance also being volatile so that the reads and writes of both variables
    // cannot be reordered.
    Provider<T> providerReference = provider;
    if (instance == UNINITIALIZED) {
      instance = providerReference.get(); // 一般情况下只会生成一个实例,多线程中可能会有多个
      // Null out the reference to the provider. We are never going to need it again, so we can make
      // it eligible for GC.
      provider = null;
    }
    return (T) instance;
  }
...
}

从上面代码可以看出使用@Reusable作用域后,利用到 Reusable 实例的 Component 会间接持有实例的引用。但是这里是用SingleCheck而不是DoubleCheck,在多线程情况下可能会生成多个实例,关于这个有疑问推荐阅读 Java 设计模式之单例模式中双重检查锁定的部分。因为@Reusable作用域目的只是可以复用之前的实例,并不需要严格地保证实例的唯一,所以使用 SingleCheck 就足够了。

Releasable references(可释放引用)

使用 Scope 注解时,Component 会间接持有绑定的依赖实例的引用,也就是说实例在 Component 还存活时无法被回收。而在 Android 中,应该尽量减少内存占用,把没有使用的对象释放,这时可以用@CanReleaseReferences标记 Scope 注解:

@Documented
@Retention(RUNTIME)
@CanReleaseReferences
@Scope
public @interface MyScope {}

然后在 Application 中注入ReleasableReferenceManager对象,在内存不足时调用releaseStrongReferences()方法把 Component 间接持有的强引用变为弱引用。

public class MyApplication extends Application {
    @Inject
    @ForReleasableReferences(MyScope.class)
    ReleasableReferenceManager myScopeReferences;

    @Override
    public void onLowMemory() {
        super.onLowMemory();
        myScopeReferences.releaseStrongReferences();
    }
...
}

这样在内存不足时,DaggerManComponent 间接持有的 Car 实例为弱引用,如果没有其他对象使用的话就可以被回收。

Binding Instances

通过前面作用域的讲解,可以清楚 Component 可以间接持有 Module 或 Inject 目标类构造函数提供的依赖实例,除了这两种方式,Component 还可以在创建 Component 的时候绑定依赖实例,用以注入。这就是@BindsInstance注解的作用,只能在 Component.Builder 中使用。

在 Android 中使用 Dagger 2 时,activity 实例经常也需要作为依赖实例用以注入,在之前只能使用 Module:

@Module
public final class HomeActivityModule {
    private final HomeActivity activity;

    public HomeActivityModule(HomeActivity activity) {
        this.activity = activity;
    }

    @Provides
    @ActivityScope  // 自定义作用域
    Activity provideActivity() {
        return activity;
    }
}

而使用@BindsInstance的话会更加简单:

@ActivityScope
@Component
public interface HomeActivityComponent {
    @Component.Builder
    interface Builder {
        @BindsInstance
        Builder activity(Activity activity);
        HomeActivityComponent build();
    }
}

注意在调用build()创建 Component 之前,所有@BindsInstance方法必须先调用。上面例子中 HomeActivityComponent 还可以注入 Activity 类型的依赖,但是不能注入 HomeActivity,因为 Dagger 2 是使用具体类型作为依据的(也就是只能使用@Inject Activity activity而不是@Inject HomeActivity activity)。

如果@BindsInstance方法的参数可能为 null,需要再用@Nullable标记,同时标注 Inject 的地方也需要用@Nullable标记。这时 Builder 也可以不调用@BindsInstance方法,这样 Component 会默认设置 instance 为 null。

总结

  • Qualifier 限定符用来解决依赖迷失问题,可以依赖实例起个别名用来区分。

  • Scope 作用域的本质是 Component 会持有与之绑定的依赖实例的引用,要想确保实例的生命周期,关键在于控制 Component 的生命周期。

下一篇文章分析 Dagger 2 种 Component 的组织方式以及 SubComponent 的概念。



作者:JohnnyShieh
链接:https://www.jianshu.com/p/9703a931c7e7
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
Dagger中Inject、Lazy、Provider的理解 初步认识Dagger中的Inject、Lazy以及Provider的过程,了解了三者的使用以及了对比它们和单例的区别 立即下载

相关推荐

设计师必看!用Figma MCP自动生成开发文档的隐藏技巧

本文为设计师揭秘利用Figma MCP协议自动生成开发文档的隐藏技巧。通过将设计稿转化为结构化数据,实现设计规范的自动化输出、版本同步与动态更新,并借助AI助手提升协作效率,彻底告别繁琐的手动标注与沟通。

berry的博客 923

Dagger 2 完全解析(二),进阶使用 Lazy、Qualifier、Scope 等

Dagger 2 完全解析系列:Dagger 2 完全解析(一),Dagger 2 的基本使用与原理Dagger 2 完全解析(二),进阶使用 Lazy、Qualifier、Scope 等Dagger 2 完全解析(三),Component 的组织关系与 SubComponentDagger 2 完全解析(四),Android 中使用 Dagger 2Dagger 2 完全解析(五),Kotlin...

晨光飞舞的专栏 1090

4.图像sensor的特性和驱动解析

例子:sensor驱动自己提供操作曝光时间的函数和获取曝光时间的函数,然后将这个函数注册到ISP库和3A算法库,3A算法库根据外部光照强度计算出一个Sensor曝光时间的设置值,ISP库得到这个设置值,然后通过Sensor之前注册的回调函数,把这个值设置到Sensor的硬件寄存器中去,实现整个过程。是为 ISP 配置正确的输入时序。(1)修改驱动源码(sambashar\Hi3518E_SDK_V1.0.3.0\package\mpp\component\isp\sensor\ar0130)

weixin_53762042的博客 3566

学习Dagger2笔记:【6】Provider & Lazy

再看@Component 我们之前使用@Component都仅仅是在其注解的接口中添加一个inject方法,作为进行依赖注入的入口,但@Component的作用远不止如此 新需求 为了深入研究@Component,我们新增两个需求 需求1 在Activity显示Computer信息时,我们要求根据当前时间(System.currentTimeMillis())单双作为区别,如果单数就显示wind...

Cmd的笔记本 1035

Type-C快充移动电源芯片避坑指南:IP5356配置全流程(支持PD3.0)

本文详细解析了英集芯IP5356芯片在Type-C快充移动电源中的应用,提供了从芯片选型、原理图设计、PCB布局到PD协议调试的全流程实战指南。文章重点剖析了如何避免散热、EMI及协议握手等常见设计陷阱,并分享了量产前的关键测试验证方法,旨在帮助硬件开发者高效打造稳定可靠的快充产品。

weixin_29235525的博客 848

从Protocol到硬件控制:揭秘高通UEFI中ABL与XBL的协作机制

本文深入解析了高通UEFI架构中ABL与XBL的协作机制,重点探讨了Protocol通信在硬件控制中的关键作用。通过对比传统GPIO控制方式,揭示了Protocol架构在安全性、可维护性和灵活性方面的优势,并提供了关机充电场景的实战案例分析及调试技巧。

weixin_29185199的博客 430

这可能是本年度最好用的 Dagger 使用教程 三(依赖注入器的依赖、子组件、Lazy、Provider)

在上一个文章中,我们介绍了 Dagger 中的限定和范围注解,现在我们将视线转移到依赖注入器来,先介绍这个组件的依赖的两种方式,再介绍两个常用的类型。

李斯维的博客空间 2578

【MFRC522】STM32与MFRC522的SPI通信优化及常见问题解析

本文深入解析了STM32与MFRC522进行SPI通信的优化方法与常见问题。从基础的硬件连接到SPI时序优化,再到关键的寄存器配置(如RFCfgReg设为0x4F以提升读卡稳定性),文章提供了详细的调试技巧和实战排坑指南,帮助开发者实现稳定高效的IC读卡应用。

yhn45678901的博客 841

android dagger2 懒加载,Dagger2使用简析(二)——@Scope、@Qualifier、@binds、dependencies、Lazy...

在了解了简单注入对象的使用后,我们将问题升级。我们平常开发中为了节省资源,在APP的生命周期内很多对象都是作为单例存在的,因此现在我们尝试解决三个问题将一个对象注入到Application中,并且保证它在整个APP的生命周期内是单例的这个对象应该符合依赖倒置原则,我们使用其抽象类来作为引用之后为了方便在MainActivity中使用它,我们还应该能够将它注入到MainActivity中1. 如何解...

weixin_39775872的博客 403

图文实录|大规模预训练模型:探讨与展望

第二期「澜舟分享会」我们邀请到来自复旦大学计算机学院邱锡鹏教授分享了“大规模预训练模型:探讨与展望”,本此演讲主要围绕大规模预训练语言模型展开讨论,并探讨大模型成功的原因、适用场景、未来发展方向以及身处大模型时代我们的机遇。

langboat_mengzi的博客 1204

【向量数据库】Milvus向量数据库 ① 从入门到实战

Milvus是专为海量高维向量设计的开源数据库,支持AI搜索、图像识别、推荐系统等场景。相比传统关系型数据库(如PostgreSQL),它更高效处理语义检索、非结构化数据存储,可毫秒级响应亿级向量查询。单机场景下,推荐配置8GB内存/32GB硬盘,支持FAISS/HNSW等索引算法,支持GPU加速。本文涵盖优快云专属部署教程(CentOS脚本/配置调优),提供避坑指南与扩展资源,并对比分析与传统数据库差异。适合算法工程师、AI开发人员快速上手,附官方下载与性能测试技巧,手把手教你搭建高效向量检索系统!

xiezhiyi007的专栏 1585

Dagger 2 完全解析(三),Component与SubComponent

Dagger 2 Component 与 SubComponent Dagger 2 完全解析(一),基本使用与原理 Dagger 2 完全解析(二), 进阶使用 Dagger 2 完全解析(三), Component 与 SubComponent 本系列文章是基于 Google Dagger 2.23.2 版本, Kotlin 1.3.21版本 理解前面两篇文章后,可以使用 Dagge...

xiaowu 专栏 2977

macOS安装Cplex+yalmip

macOS安装Cplex+yalmip

DS 4248

Dagger2利器系列二:懒/重加载+Component 的组织关系

目录 一:懒/重加载 1.1 Dagger2 中的懒加载 1.2Provider 强制重新加载 二:Component 的组织依赖关系 2.1 前言 2.2 Component 的组织关系 2.2.1 依赖关系 2.2.3 继承关系 2.3 依赖关系 vs 继承关系 2.4 SubComponent 的其他问题 2.4.1 抽象工厂方法定义继承关系 2.4.2 重复的 M...

许进进的博客 5652

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

Dagger2进阶-简说SubComponent和Qualifier

前言 Dagger2的介绍和配置 Dagger2基础的使用 Dagger2进阶-编译生成源码解读 Dagger2进阶-范围的控制(Scope和Singleton) Dagger2进阶-Scope的源码探究 Dagger2进阶-简说SubComponent和Qualifier ...

木木baby的博客 896

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

Dagger 2 完全解析(四),Android 中使用 Dagger 2

Dagger 2 完全解析系列:Dagger 2 完全解析(一),Dagger 2 的基本使用与原理Dagger 2 完全解析(二),进阶使用 Lazy、Qualifier、Scope 等Dagger 2 完全解析(三),Component 的组织关系与 SubComponentDagger 2 完全解析(四),Android 中使用 Dagger 2Dagger 2 完全解析(五),Kotlin...

晨光飞舞的专栏 476

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Dagger依赖注入终极指南:Component、Module、Inject核心概念详解

Dagger是一个专为Android和Java设计的快速依赖注入框架,通过注解处理器自动生成代码,帮助开发者轻松管理对象依赖关系。本文将深入解析Dagger的三大核心概念——Component、Module和Inject,让你快速掌握依赖注入的精髓。 ## 🧩 Dagger核心三要素解析 ### @Inject:依赖注入的起点 `@Inject`注解是Dagger依赖注入的基础,它有两种主要

gitblog_00522的博客 1208

初识Dagger2记录总结

b站的教学视频: 视频链接 Dagger是一个依赖注入框架,降低代码间的耦合度,主要通过注解的方式来使用它。 . 首先把Dagger2引入项目: java中引入: //Dagger2 api 'com.google.dagger:dagger:2.25.2' annotationProcessor 'com.google.dagger:dagger-compiler:2.25...

qq_38287890的博客 178

详解 Dagger2 的 @Scope 和 @Subcomponent

个人觉得网上关于 dagger2 文章中关于 @Scope 和 @Subcomponent 解释的并不是很详细,也可能是我个人能力有限不能够理解,所以写下这篇文章,希望能够帮助后人更方便的入门。 @Scope 是什么 @Scpoe 的使用 @Subcomponent 是什么 @Subcomponent 的使用 @Subcomponent 和 @Component 的实际使用场景定义 @Scope 是

joker 2901

Dagger.Android — Dagger2进阶

一,前期基础知识储备 参考笔者之前的文章《依赖注入框架-Dagger2 精炼详解》,里面有Dagger2的常规用法——@Inject,@Component,@Module,@Provides这些基本注解。 这里沿用上篇文章中示例,在Activity中完成一个类的注入,代码如下: public class HttpActivity extends AppCompatActivity { ...

Chin_Style的博客 531

Vite 配置文件报 This package is ESM only 怎么解决?

运行 `vite` 启动开发服务器或 `vite build` 构建时,如果配置文件里引入的某个依赖是 ESM only 包,而配置本身被 Node.js 当作 CommonJS 加载,就会在加载配置阶段失败。Vite 官方 troubleshooting 文档给出了两种报错形态(下面是文档中的示例文本,`"foo"` 和路径在你的实际报错里会替换成真实的依赖名与文件路径): ``` Faile

gitblog_01061的博客 1136

google四件套之Dagger2。从入门到爱不释手,之:Dagger2基础知识及在Java中使用(1)

前言 网上都说Dagger2是比较难上手的,我在看了大量资料和使用时也遇到了很多不懂或者模糊的知识点,而且大部分博客资料都比较古老。突然有那么一瞬间,突然明白了所以然,故总结了3篇文章。话说在java中使用还是很繁琐的,不要怕带你真正上手,并运用到我们的Android项目中去。 本次Dagger2讲解总共分4篇: 1、Dagger2基础知识及在Java中使用(1) 2、Dagger2基础知识及在J...

岩浆李的游鱼 1392

Dagger2单例(四)

Dagger2单例(四) 我们就继续用前面的例子开始讲了,如果我使用了两个对象: class CoffeeMaker { @Inject Heater heater; @Inject Heater heater2; CoffeeMaker() { CoffeeComponent component = DaggerCoffeeC...

Charon_Chui的专栏 1469

hooks 库 useUnmount:在组件卸载时执行清理逻辑的 React Hook 源码解析与实战

`useUnmount` 是当前仓库(GitHub 加速计划 / hooks / hooks,即 ahooks 的镜像仓库)提供的一个生命周期类 Hook,用于在组件卸载(unmount)时执行指定的函数。它的典型应用场景包括:清理定时器、取消网络请求、移除全局事件监听、断开 WebSocket 连接、重置第三方库状态等,避免组件卸载后仍然产生副作用而导致内存泄漏或状态更新报错。读完本文,你将掌握

gitblog_00505的博客 921

Bandhook-Kotlin依赖注入实战:Dagger 2在Kotlin项目中的完整应用

Bandhook-Kotlin是一个完全使用Kotlin语言编写的Android音乐展示应用,本文将详细介绍如何在该项目中使用Dagger 2实现依赖注入,帮助开发者构建更清晰、可维护的代码架构。 ## 依赖注入基础:为什么选择Dagger 2? 依赖注入是一种设计模式,它可以帮助我们减少类之间的耦合,提高代码的可测试性和可维护性。在Android开发中,Dagger 2是最流行的依赖注入框架

gitblog_00389的博客 414

Android开发终极指南:Dagger依赖注入完整教程

Android开发终极指南为你提供全面的Dagger依赖注入解决方案,帮助开发者简化代码结构、提升应用性能。本教程将从基础概念到高级应用,带你掌握Dagger在Android项目中的实战技巧。 ## 为什么选择Dagger进行依赖注入? 依赖注入是Android开发中的重要设计模式,它能够降低代码耦合度、提高可测试性和可维护性。Dagger作为Google官方推荐的依赖注入库,通过编译时生成代

gitblog_00700的博客 444
上一篇: Dagger 2 完全解析(二),进阶使用 Lazy、Qualifier、Scope 等
下一篇: Dagger 2 完全解析(四),Android 中使用 Dagger 2
candyguy242
博客等级 码龄17年 63粉丝 37原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值