热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

AndroidDagger2使用小结

都说不用dagger2的mvp模式都是耍流氓,但是,但是我之前一直都在耍流氓?所以这两天入门了一下dagger2。参考的项目时googlesamplesandroid-archit

都说不用 dagger2mvp 模式都是耍流氓,但是,但是我之前一直都在耍流氓?所以这两天入门了一下 dagger2

参考的项目时googlesamples/android-architecturedagger 分支。还有就是 dagger 里面自带的example。

dagger的定义

A fast dependency injector for Android and Java.
Android和Java的依赖快速注入器。

定义是如此的简洁,那么到底是撒意思呢?应该如何理解?我现在的理解就是它可以快速自动的构建出我们所需要的依赖对象,这里的依赖对象可以理解为某一个成员变量。例如在 MVP 中,VP 层就是互相关联的, V 要依赖对应的 P,而 P 也要依赖对应的 Vdagger 能解决的就是这种依赖关系,通过注入的方式,将双方的耦合再次降低,在实际的使用中体现为一个注解想要的对象就创建好了,咱们不用再去管理所依赖对象的创建等情况了。

dagger 入门

注入,肯定涉及到 将什么 注入 到哪里 的三个问题,那接下来就围绕着三个方面展开咯!

自定义 Module 注入

Module 中使用 @Provides 提供相关的注入对象是第一种实现方式。具体做法是定义一个类,加上 @Moudule 的注解。然后在里面使用 @Provides 定义返回注入对象的方法。

@Module
public final class ApplicationModule {
private final Context mContext;
ApplicationModule(Context context) {
mCOntext= context;
}
@Provides
Context provideContext() {
return mContext;
}
@Provides
DailyApiService provideDailyApiService() {
return BaseDataManager.getDailyApiService();
}
@Provides
int provideAge() {
return 500;
}
}

《Android Dagger2使用小结》 Provider.png

关于 Module 中的方法,按照官方解释咱们需要有以下的注意事项,每个方法应该是无参的,返回的就是需要注入的类型的。

构造方法注入

如果我们可以访问对应的构造方法,那儿这里也提供了另外一种注入的方式,就是在构造方法是使用 @Inject 的注解了。

《Android Dagger2使用小结》 Inject相关.png

这个注解可以定义在构造方法上,方法上,字段上,但是这里有一个优先顺序,就是最先执行构造方法上的,其次是相关字段的,最后就是相关方法的。字段的权限不能是私有的。如果有多个构造方法,@Inject只能指定其中的一个。

@Inject
public Person(String birthday, String name) {
this.birthday = birthday;
this.name = name;
}

到这里基本上差不多说完了第一部分 将什么 的问题。

注入 到哪里

对于 注入 到哪里 这两个问题,这里首先要引入 @Component 的注解了,举个场景,例如我们在 Activity 里经常会使用到全局的 Application ,在 Application 的初始化中也可能初始化好某些类( ApiService ),那么这个关系就是 Activity 依赖 Application , Application 依赖 ApiService

首先我们定义一个 AppComponent ,这是一个接口类,dagger 会自动生成具体实现类。 @Component 定义了需要注入的 Modules 对象 还有可以指定 所依赖的其他 Component 组件。对于 @Component 的使用,它应该定义在接口或者抽象类中,并且里面至少要有一个方法,至于每个方法的命名,没有特别的指定符合相关命名规范就好了。

@Singleton
@Component(modules = { ApplicationModule.class})
public interface AppComponent {
Context context();
DailyApiService getdailyApiService();
int getAge();
}

通过以上步骤,就已经定义好了 Component 和需要注入的 Module 了,然后在 APP 中来试着注入我们定义的 age 字段看看。这里第一个问题是咱们怎么获取对应的 AppComponent 实现类呢?定义好了 ComponentModule 之后记得 rebuild 一下,然后 dagger 会自动生成对应的 Component 实现类,名字的话就是 Dagger+ComponentName (如果你是内部类的话似乎还有外部的 ClassName ),然后调用其的 builder() 方法,传入依赖的 Module 或者 Component ,最后就创建好了对应的实现类了。

但是到这里,你会发现 log 显示的 age 根本就不是我们指定的 500,为什么呢?怎么就没有注入成功呢?!因为我们还没有执行真正的注入这个动作啊,还缺了最后一个方法,执行我们的注入,上面只是把对应的Component 创建出来了而已,并没有注入呢!那么最后这一步怎么定义呢?

《Android Dagger2使用小结》 Inject_Method.png

根据文档,我们需要在 AppComponent 接口中再定义一个方法,这个方法只能有一个参数,这个参数就是指定我们之前所说的哪里,这个方法可以返回 void 或者该类型,咱们通常的写法都是返回 void 的。在接口中添加该方法,修改了 Component 记得要 rebuild 哟。

void inject(App app);

App 中最后调用 mAppComponent.inject(this) ,再次运行,这次就可以看到已经注入成功了,到这里,dagger 的入门就搞定了。用一个比喻就是 Component 相当于一个注射器,是个容器,还有一个针头,里面装的就是使用 @Provides 或者 @Inject 定义的需要注入的对象,通过inject(Type type) 的方法指定需要注入到指定的对象中,这样就完成了整个注入过程。

dagger进阶

相同类型多次注入

@Qualifier
如果我们在 Module 中有重复的类型返回,例如我定义两个 int 类型的providesModule 中的话,编译直接会报错:

xxx is bound multiple times:

那如果我们真的需要注入同一类型多次呢,这个问题总会有解决方案的吧?要是真的这么坑估计也没人用 dagger 了吧!哈哈。下面说明这个问题应该如何解决。

dagger 中具有相同类型返回的情况时,可以使用@Qualifier 的注解来区分,而 dagger 已经为我们提供了一个其子类 @Named("xx") 的注解。

例如在上面的 Module 中可以如果需要返回两个 int 类型的话需要这么声明:

@Singleton
@Provides
@Named("number")
int provideNumber() {
return 5;
}
@Provides
@Named("age")
int provideAge() {
return 500;
}

并且在调用的位置,也需要使用同样的 @Named("age") 的来指定你需要注入的是哪个具体的对象。

懒加载

在上面的比喻中,一针扎进去,是撒都给你打进去了,那么如果有些我想要在调用的时候才加载呢?这里 dagger 提供了 Lazy 的方式来注入。

对应的获取就是:

@Inject
Lazy str;//延迟加载

你没有看错,就是这么简单,获取时使用 Lazy 包装一下就行了,在真正需要加载的时候调用 str.get()来加载。

获取某一个注入对象多次

比如我们需要一次性创建出10个 Person 对象,这个怎么处理呢?这里就需要使用 Provider 的类来指定了。获取方式也是 get() 就好了,每次都会创建出行的对象。

Component 的依赖

如果我们定义了某一个 ActivityComponent ,并且它依赖咱们的 AppComponent 里面的 APIService 的话就要这样定义了:

@ActivityScope
@Component(dependencies = AppComponent.class, modules = ListStoryPresenterModule.class)
public interface ListStoryComponent {
void inject(ListStory view);
}

AppComponent 中需要将获取 APIService 的方法暴露出来,不然还是无法注入成功的。

那如果我觉得暴露这些方法太麻烦了,那需要怎么办呢?最简单就是使用 @SubComponent ,在所属的父 Component 中定义一个 SubComponent,该 SubComponent 中将会包含父 Component 的所有方法。父 Component 不显示声明都可以。

@ActivityScope
@Component(dependencies = AppComponent.class, modules = ListStoryPresenterModule.class)
public interface ListStoryComponent {
String getName(String name);
ListPresenter.View getView();
SubComponent getSubComponent(SubModule module);
}
@Subcomponent(modules = SubModule.class)
public interface SubComponent {
void inject(ListStory context);
}

子类注入

void inject(Activity view) 注入的方法是可以接受该类型的子类的,但是在子类中定义的 @Inject 是无效的,比如说上面说的那个 AppComponent 的例子中如果最后申明的注入方法是:

void inject(Application app);

你会发现,age 的值一样不会注入成功的。再举官方的实例:我们定义了 void inject(Self self) 的方法,只有A 和 B 能注入,其子类中的C是无法注入的。

class Parent {
@Inject A a;
}
class Self extends Parent {
@Inject B b;
}
class Child extends Self {
@Inject C c;
}

那么需要怎么解决这个问题呢?目前我的感觉只能在对应的 Component 中定义一系列需要实现的子类的注入方法咯。

void inject(App app);
void inject(SubActivityA activity);
void inject(SubActivityB activity);

作用域

最后还有一个问题就是 Component 的作用域,@Scope 就是其中来限定相关作用域,例如说我们需要初始化一些全局的工具类,像 GsonSharedPreferences 这些,那我们就需要一个单例就行了,那么 dagger 如何保证注入的对象就是单例的呢?那就需要使用这个@Scope的注解了。然后应该在基类里面初始化一个全局通用的 Component ,然后在每个子类里面一次调用注入的方法。另外这个注解 ComponentModule 是要成对使用的,不然会报错的。然后在具体的子类中实现initInject()的方法。 对了,@Scope 已经实现了的是 @Singleton,我们可以直接使用 。

public abstract class BaseActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AppComponent appCompOnent= ((App) getApplication()).getAppComponent();
initInject(appComponent);
}
public abstract void initInject(AppComponent appComponent);
}

小结

使用 dagger 的好处就是在有依赖对象的时候,进一步不用去考虑所依赖对象的创建什么的,对我们就是隐藏了构造对应对象的过程,省去了创建的相关代码。当然我也只是这两天刚刚上手使用 dagger,所以不免有相关优势没有挖掘出来,或者自己有相关的理解偏差。另外建议大家多看看 dagger的相关注解,除了是英文这个缺点,真的很详尽的。


推荐阅读
  • 本文介绍了如何使用C#制作Java+Mysql+Tomcat环境安装程序,实现一键式安装。通过将JDK、Mysql、Tomcat三者制作成一个安装包,解决了客户在安装软件时的复杂配置和繁琐问题,便于管理软件版本和系统集成。具体步骤包括配置JDK环境变量和安装Mysql服务,其中使用了MySQL Server 5.5社区版和my.ini文件。安装方法为通过命令行将目录转到mysql的bin目录下,执行mysqld --install MySQL5命令。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 本文介绍了一个在线急等问题解决方法,即如何统计数据库中某个字段下的所有数据,并将结果显示在文本框里。作者提到了自己是一个菜鸟,希望能够得到帮助。作者使用的是ACCESS数据库,并且给出了一个例子,希望得到的结果是560。作者还提到自己已经尝试了使用"select sum(字段2) from 表名"的语句,得到的结果是650,但不知道如何得到560。希望能够得到解决方案。 ... [详细]
  • springmvc学习笔记(十):控制器业务方法中通过注解实现封装Javabean接收表单提交的数据
    本文介绍了在springmvc学习笔记系列的第十篇中,控制器的业务方法中如何通过注解实现封装Javabean来接收表单提交的数据。同时还讨论了当有多个注册表单且字段完全相同时,如何将其交给同一个控制器处理。 ... [详细]
  • Spring学习(4):Spring管理对象之间的关联关系
    本文是关于Spring学习的第四篇文章,讲述了Spring框架中管理对象之间的关联关系。文章介绍了MessageService类和MessagePrinter类的实现,并解释了它们之间的关联关系。通过学习本文,读者可以了解Spring框架中对象之间的关联关系的概念和实现方式。 ... [详细]
  • 如何查询zone下的表的信息
    本文介绍了如何通过TcaplusDB知识库查询zone下的表的信息。包括请求地址、GET请求参数说明、返回参数说明等内容。通过curl方法发起请求,并提供了请求示例。 ... [详细]
  • Android系统源码分析Zygote和SystemServer启动过程详解
    本文详细解析了Android系统源码中Zygote和SystemServer的启动过程。首先介绍了系统framework层启动的内容,帮助理解四大组件的启动和管理过程。接着介绍了AMS、PMS等系统服务的作用和调用方式。然后详细分析了Zygote的启动过程,解释了Zygote在Android启动过程中的决定作用。最后通过时序图展示了整个过程。 ... [详细]
  • 开发笔记:Dagger2 探索记3——两大进阶组件
        今天要讲的时@Scope这个组件。为什么说它是进阶组件,就是因为它基本上没作用,但在理解了基本组件之后又必须用到。 ... [详细]
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
author-avatar
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有