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

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

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

public class User {

	....
.... @Inject
public User() {
} ....
.... }

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

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

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

public class MainActivity extends AppCompatActivity {

    @Inject
User user;
@Inject
User user2;
private TextView tv;
private TextView tv2; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerActivityComponent.builder().build().inject(this);
tv = ((TextView) findViewById(R.id.tv));
tv2 = ((TextView) findViewById(R.id.tv2));
tv.setText(user.toString());
tv2.setText(user2.toString());
}
}

显示结果如下:

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

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

@Singleton
public class User { ....
.... @Inject
public User() {
} ....
.... }


2.给ActivityComponent添加上@Singleton注解

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

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

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

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

@Module
public class UserModule {
@Provides
@Singleton
User providesUser() {
return new User();
}
}

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

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

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

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

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

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

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

@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface UserScope {
}

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

@Module
public class UserModule {
@Provides
@UserScope
User providesUser() {
return new User();
}
}

@UserScope
@Component(modules = UserModule.class)
public interface ActivityComponent {
void inject(MainActivity activity); void inject(BActivity activity);
}

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

public class MyApp extends Application {
ActivityComponent activityComponent;
@Override
public void onCreate() {
super.onCreate();
activityComponent = DaggerActivityComponent.builder().userModule(new UserModule()).build();
} ActivityComponent getActivityComponent(){
return activityComponent;
}
}

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

    @Inject
User user;
@Inject
User user2;
private TextView tv;
private TextView tv2; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// DaggerActivityComponent.builder().userModule(new UserModule()).build().inject(this);
((MyApp) getApplication()).getActivityComponent().inject(this);
tv = ((TextView) findViewById(R.id.tv));
tv2 = ((TextView) findViewById(R.id.tv2));
tv.setText(user.toString());
tv2.setText(user2.toString());
}

BActivity如下:

    @Inject
User user; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_b);
((MyApp) getApplication()).getActivityComponent().inject(this);
TextView tv = (TextView) findViewById(R.id.tv);
tv.setText(user.toString());
}

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

CUserModule如下:

@Module
public class CUserModule {
@Provides
User providesUser() {
return new User();
}
}

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

CActivityComponent如下:

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

在CActivity中注入依赖:

    @Inject
User user;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_c);
DaggerCActivityComponent.builder().cUserModule(new CUserModule()).build().inject(this);
TextView tv = (TextView) findViewById(R.id.tv);
tv.setText(user.toString());
}

运行结果如下:

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

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

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

Scope的使用,如何实现单例?

这个迷之Scope也是有点难以理解,我们在哪里使用到了Scope呢。在我们的AppComponent中添加了一个注解为@Singleton,@Singleton就是一个Scope,据说可以实现单例哟。。。难道这样就实现了单例模式?我刚刚开始是这样理解的。直到仔细的看了几遍这篇文章我才知道并不是这样的。

事实上@Sinleton中并没有创建单例的能力,那么AppComponent中提供的依赖注入是如何实现单例的呢。其实这个原理很贱单。

首先Module提供了创建实例的方法,接着AppComponent中对Module进行管理,最后AppComponent在自定义Applicaiton中被实例化了一次。

这个实例化了一次是最重要的呀。仅仅被实例化了一次,那不就是单例么。就是这么简单呀。

可能有些童靴当时就不乐意了,那既然这样都已经实现了单例,那么这个@Singltop还要来何用?不是多此一举吗。

其实@Singletop还有有一些作用的,首先一方面能让你直面的了解到这是一个单例,其次这个@Singletop能够更好的管理Modlue和Component之间的关系。

Dagger2需要保证Component和Module是匹配的,就需要用到这个注解。

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. Layout Resource官方教程(1)简介

    Layout Resource SEE ALSO Layouts A layout resource defines the architecture for the UI in an Activit ...

  2. Service Oriented Architecture

    What is Service Oriented Architecture (SOA)? There have been so many interpretations of this through ...

  3. hadoop2.2编程:各种API

    hadoop2.2 API http://hadoop.apache.org/docs/r0.23.9/api/index.html junit API http://junit.org/javado ...

  4. API函数

    1. API之网络函数 WNetAddConnection 创建同一个网络资源的永久性连接 WNetAddConnection2 创建同一个网络资源的连接 WNetAddConnection3 创建同 ...

  5. U制作LFS linux

    我希望自己的LFS运行在U盘上,远期目标是要制作一个基于LFS的编程练习U盘,方便自己的编程练习.今天算是工作的第一步,先把LFS做到U盘上. 把Linux做到U盘上通常的做法是采用两步启动法:先生成 ...

  6. epub3 in action: epub3文件格式简介

    epub3文件就是一个符合epub3标准,以epub为扩展名的zip压缩文件.epub3标准则是基于html5.css3.svg等web标准以及mathML等来展示内容.下图就是一个简单epub3文件 ...

  7. Java&MySQL Type Mapping

    MySQL Type Name Return value of GetColumnClassName Returned as Java Class BIT(1) (new in MySQL-5.0) ...

  8. 【转】小解DCT与DFT

    这学期当本科生数字图像处理的助教老师,为使学生更好地理解DCF和DFT之间的关系给出三题,大家可以思考一下,看一下自己对这些最简单的变换是否真正理解. 1.求解序列f(n)=[2,3,3,4,4,3, ...

  9. Java 并发之共享对象

    上一篇文章说的是,避免多个线程在同一时间访问对象中的同一数据,这篇文章来详细说说共享和发布对象. 在没有同步的情况下,我们无法预料编译器.处理器安排操作执行的顺序,经常会发生以为“一定会”发生的动作实 ...

  10. UltraISO PE(软碟通) v9.6.2.3059 注册码

    注册码: 王涛7C81-1689-4046-626F