关于Dagger2使用的基础如果你还不了解,可以参考我的上一篇文章解锁Dagger2使用姿势(一),这有助于你理解本篇文章。

OK,我们在上篇文章介绍另外Dagger2使用过程中四个基本的注解,分别是@Module、@Provides、@Inject以及@Component。今天我想来说说Dagger2中另外一个注解,那就是@Scope注解。看网上的资料,大家基本上都知道@Scope是用来给依赖划定作用域的,那我今天就来来说说这个作用域的问题。

首先Dagger2中有一个现成的作用域注解,那就是@Singleton,其实这个@Singleton还是由Java提供的。那么这个注解的作用域就是让我们的依赖成为单例模式。比如下面一个例子:假设我有一个用户对象,如下:

  1. public class User {
  2.  
  3. ....
  4. ....
  5.  
  6. @Inject
  7. public User() {
  8. }
  9.  
  10. ....
  11. ....
  12.  
  13. }

我这里暂时先用@Inject来注解这个用户对象,避免使用Module,然后我需要一个Component来注入这个User对象到我的Activity中,我的Component如下:

  1. @Component
  2. public interface ActivityComponent {
  3. void inject(MainActivity activity);
  4. }

OK,然后我在我的MainActivity中初始化User对象,并将其地址显示出来:

  1. public class MainActivity extends AppCompatActivity {
  2.  
  3. @Inject
  4. User user;
  5. @Inject
  6. User user2;
  7. private TextView tv;
  8. private TextView tv2;
  9.  
  10. @Override
  11. protected void onCreate(Bundle savedInstanceState) {
  12. super.onCreate(savedInstanceState);
  13. setContentView(R.layout.activity_main);
  14. DaggerActivityComponent.builder().build().inject(this);
  15. tv = ((TextView) findViewById(R.id.tv));
  16. tv2 = ((TextView) findViewById(R.id.tv2));
  17. tv.setText(user.toString());
  18. tv2.setText(user2.toString());
  19. }
  20. }

显示结果如下:

OK ,大家看到这完全是两个不同的对象,两个对象的引用地址完全不一样。那如果我想让User变为一个单例模式该怎么办呢?其实很简单,添加上@Singleton注解就可以了,在哪里添加呢?两个地方:

1.给User类添加上@Singleton注解:

  1. @Singleton
  2. public class User {
  3.  
  4. ....
  5. ....
  6.  
  7. @Inject
  8. public User() {
  9. }
  10.  
  11. ....
  12. ....
  13.  
  14. }


2.给ActivityComponent添加上@Singleton注解

  1. @Singleton
  2. @Component
  3. public interface ActivityComponent {
  4. void inject(MainActivity activity);
  5. }

如此之后我再运行,结果如下:

OK,这个时候User对象就会以单例形式存在于我的App中了。OK,那如果我的项目中有Module,又该如何使我的User对象单例呢?

很简单,在Module中提供User对象,提供User对象的方法需要有单例注解:

  1. @Module
  2. public class UserModule {
  3. @Provides
  4. @Singleton
  5. User providesUser() {
  6. return new User();
  7. }
  8. }

这个时候User对象上的注解就都可以去掉了,然后稍微修改一下ActivityComponent,如下:

  1. @Singleton
  2. @Component(modules = UserModule.class)
  3. public interface ActivityComponent {
  4. void inject(MainActivity activity);
  5. }

然后MainActivity中初始化的代码也要稍微修改一下下:

  1. DaggerActivityComponent.builder().userModule(new UserModule()).build().inject(this);

然后再运行,依然是单例模式。

OK,那我们知道@Singleton注解实际上实现的是一个全局单例模式,在实际开发中我们可能还需要一种局部单例的控件(这个应该是更常用),比如说我们有三个Activity,MainActivity,BActivity和CActivity,我们想让MainActivity和BActivity共享同一个实例,而让CActivity获取另外一个实例,这又该怎么实现呢?在Dagger2中,我们可以通过自定义Scope来实现局部单例。爽歪歪吧!OK,那就动手吧:

首先让我们先来定义一个局部作用域:

  1. @Scope
  2. @Retention(RetentionPolicy.RUNTIME)
  3. public @interface UserScope {
  4. }

然后在我们的UserModule和ActivityComponent中应用该局部作用域:

  1. @Module
  2. public class UserModule {
  3. @Provides
  4. @UserScope
  5. User providesUser() {
  6. return new User();
  7. }
  8. }

  1. @UserScope
  2. @Component(modules = UserModule.class)
  3. public interface ActivityComponent {
  4. void inject(MainActivity activity);
  5.  
  6. void inject(BActivity activity);
  7. }

请大家注意,我的ActivityComponent作为一个注入器只可以向MainActivity和BActivity两个Activity中注入依赖,不可以向CActivity中注入依赖。最后,要让该局部作用域产生单例效果,需要我们在自定义的Appliation类中来初始化这个Component,如下:

  1. public class MyApp extends Application {
  2. ActivityComponent activityComponent;
  3. @Override
  4. public void onCreate() {
  5. super.onCreate();
  6. activityComponent = DaggerActivityComponent.builder().userModule(new UserModule()).build();
  7. }
  8.  
  9. ActivityComponent getActivityComponent(){
  10. return activityComponent;
  11. }
  12. }

接下来我们在MainActivity和BActivity中注入依赖,MainActivity如下:

  1. @Inject
  2. User user;
  3. @Inject
  4. User user2;
  5. private TextView tv;
  6. private TextView tv2;
  7.  
  8. @Override
  9. protected void onCreate(Bundle savedInstanceState) {
  10. super.onCreate(savedInstanceState);
  11. setContentView(R.layout.activity_main);
  12. // DaggerActivityComponent.builder().userModule(new UserModule()).build().inject(this);
  13. ((MyApp) getApplication()).getActivityComponent().inject(this);
  14. tv = ((TextView) findViewById(R.id.tv));
  15. tv2 = ((TextView) findViewById(R.id.tv2));
  16. tv.setText(user.toString());
  17. tv2.setText(user2.toString());
  18. }

BActivity如下:

  1. @Inject
  2. User user;
  3.  
  4. @Override
  5. protected void onCreate(Bundle savedInstanceState) {
  6. super.onCreate(savedInstanceState);
  7. setContentView(R.layout.activity_b);
  8. ((MyApp) getApplication()).getActivityComponent().inject(this);
  9. TextView tv = (TextView) findViewById(R.id.tv);
  10. tv.setText(user.toString());
  11. }

那么如果我还想在CActivity中使用User对象该怎么办呢?再来一个CUserModule和CActivityComponent呗!

CUserModule如下:

  1. @Module
  2. public class CUserModule {
  3. @Provides
  4. User providesUser() {
  5. return new User();
  6. }
  7. }

这里我没有再注明单例了哦!

CActivityComponent如下:

  1. @Component(modules = CUserModule.class)
  2. public interface CActivityComponent {
  3. void inject(CActivity activity);
  4. }

在CActivity中注入依赖:

  1. @Inject
  2. User user;
  3. @Override
  4. protected void onCreate(Bundle savedInstanceState) {
  5. super.onCreate(savedInstanceState);
  6. setContentView(R.layout.activity_c);
  7. DaggerCActivityComponent.builder().cUserModule(new CUserModule()).build().inject(this);
  8. TextView tv = (TextView) findViewById(R.id.tv);
  9. tv.setText(user.toString());
  10. }

运行结果如下:

大家看到,MainActivity和BActivity是同一个实例,而CActivity则是另外一个实例。

那么可能会有小伙伴问@UserScope在这里到底起了什么作用?我引用网上一段话:

以下文字来源:http://blog.csdn.net/u012943767/article/details/51941872

  1. Scope的使用,如何实现单例?
  2.  
  3. 这个迷之Scope也是有点难以理解,我们在哪里使用到了Scope呢。在我们的AppComponent中添加了一个注解为@Singleton@Singleton就是一个Scope,据说可以实现单例哟。。。难道这样就实现了单例模式?我刚刚开始是这样理解的。直到仔细的看了几遍这篇文章我才知道并不是这样的。
  4.  
  5. 事实上@Sinleton中并没有创建单例的能力,那么AppComponent中提供的依赖注入是如何实现单例的呢。其实这个原理很贱单。
  6.  
  7. 首先Module提供了创建实例的方法,接着AppComponent中对Module进行管理,最后AppComponent在自定义Applicaiton中被实例化了一次。
  8.  
  9. 这个实例化了一次是最重要的呀。仅仅被实例化了一次,那不就是单例么。就是这么简单呀。
  10.  
  11. 可能有些童靴当时就不乐意了,那既然这样都已经实现了单例,那么这个@Singltop还要来何用?不是多此一举吗。
  12.  
  13. 其实@Singletop还有有一些作用的,首先一方面能让你直面的了解到这是一个单例,其次这个@Singletop能够更好的管理ModlueComponent之间的关系。
  14.  
  15. Dagger2需要保证ComponentModule是匹配的,就需要用到这个注解。

OK,这就是Dagger2中@Scope注解的使用。后面我再来介绍Component之间的依赖关系。

以上。

Demo下载http://download.csdn.net/detail/u012702547/9603997

解锁Dagger2使用姿势(二) 之带你理解@Scope的更多相关文章

  1. 解锁Dagger2使用姿势(一)

    毫无疑问,Dagger2的 上手是有门槛的,有门槛是因为它里边的概念多,用起来复杂,可是一旦你学会了Dagger2的使用,你一定会爱不释手的.与ButterKnife和AndroidAnnotatio ...

  2. [转帖]从零开始入门 K8s | 手把手带你理解 etcd

    从零开始入门 K8s | 手把手带你理解 etcd https://zhuanlan.zhihu.com/p/96721097 导读:etcd 是用于共享配置和服务发现的分布式.一致性的 KV 存储系 ...

  3. 手摸手带你理解Vue的Watch原理

    前言 watch 是由用户定义的数据监听,当监听的属性发生改变就会触发回调,这项配置在业务中是很常用.在面试时,也是必问知识点,一般会用作和 computed 进行比较. 那么本文就来带大家从源码理解 ...

  4. 大白话说Java泛型(二):深入理解通配符

    文章首发于[博客园-陈树义],点击跳转到原文<大白话说Java泛型(二):深入理解通配符> 上篇文章<大白话说Java泛型(一):入门.原理.使用>,我们讲了泛型的产生缘由以及 ...

  5. 一个故事带你理解if __name__ == '__main__'

    如果你刚刚接触python,相信会在看别人的程序的时候会遇到if __name__ == '__main__'酱紫的语法,如果当时没看懂现在也一知半解的话,看下去,本文可以帮你解决这个问题. 大家都知 ...

  6. JDK1.8源码逐字逐句带你理解LinkedHashMap底层

    注意 我希望看这篇的文章的小伙伴如果没有了解过HashMap那么可以先看看我这篇文章:http://blog.csdn.net/u012403290/article/details/65442646, ...

  7. 手摸手带你理解Vue的Computed原理

    前言 computed 在 Vue 中是很常用的属性配置,它能够随着依赖属性的变化而变化,为我们带来很大便利.那么本文就来带大家全面理解 computed 的内部原理以及工作流程. 在这之前,希望你能 ...

  8. Pthread 并发编程(二)——自底向上深入理解线程

    Pthread 并发编程(二)--自底向上深入理解线程 前言 在本篇文章当中主要给大家介绍线程最基本的组成元素,以及在 pthread 当中给我们提供的一些线程的基本机制,因为很多语言的线程机制就是建 ...

  9. Android自己定义ViewGroup(二)——带悬停标题的ExpandableListView

    项目里要加一个点击可收缩展开的列表,要求带悬停标题,详细效果例如以下图: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fon ...

随机推荐

  1. Java:List,ArrayList和LinkList的区别

    1.大学数据结构中ArrayList是实现了基于动态数组的数据结构,LinkList基于链表的数据结构 2.对于随机访问get和set,ArrayList优于LinkList,因为LinkedList ...

  2. Eclipse下Properties解析(重要的可修改的会用红笔标注)

    以项目为例,打开Properties界面 显示如图: Resource(资源) 展开为 Builders Hibernate Settings Java Build Path(个人认为最重要的) Ja ...

  3. 实验一DOS报告

    实验一.DOS命令解释程序的编写实验 13物联网  李名贵  201306104123 一.        实验目的 (1)认识DOS: (2)掌握命令解释程序的原理: (3)掌握简单的DOS调用方法 ...

  4. URAL1635. Mnemonics and Palindromes(DP)

    链接 先初始化一下所有的回文串 再O(n*n)DP 输出路径dfs 刚开始存所有回文 ME了 后来发现用不着 改了改了OK了 数据还挺强 #include <iostream> #incl ...

  5. poj3140Contestants Division

    链接 这叫树形DP吗..?断开某条边 求剩下两颗树数权值和的差最小 dfs一遍 枚举边 查了n久 wa n次  dp数组没初始化.. 在poj上1A感觉应该挺爽 #include <iostre ...

  6. BZOJ_1609_[Usaco2008_Feb]_Eating_Together_麻烦的聚餐_(动态规划,LIS)

    描述 http://www.lydsy.com/JudgeOnline/problem.php?id=1609 给出一串由1,2,3组成的数,求最少需要改动多少个数,使其成为不降或不升序列. 分析 法 ...

  7. 【转】 如何查看linux版本 如何查看LINUX是多少位

    原文网址:http://blog.csdn.net/hongweigg/article/details/7192471 一.如何得知自己正在使用的linux是什么版本呢,下面的几种方法将给你带来答案! ...

  8. Dell笔记本禁用触摸板的方法

    一·找到触摸板驱动所在的文件夹(其他型号 的本本,请自己探索一下,找到驱动在哪就行),一般 在 C:\program files\delltpad 中(若没有请下载安 装 ),如图: 二·双击 Del ...

  9. HTTP请求中的缓存(cache)机制

    http://www.chaorenmao.com/blog/?p=79 流程 当资源第一次被访问的时候,HTTP头部如下 (Request-Line)  GET /a.html HTTP/1.1Ho ...

  10. Log4Net 配置和使用

    转:http://www.cnblogs.com/chencidi/archive/2010/01/12/1645291.html web.config配置如下: <?xml version=& ...