解锁Dagger2使用姿势(二) 之带你理解@Scope
关于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的更多相关文章
- 解锁Dagger2使用姿势(一)
毫无疑问,Dagger2的 上手是有门槛的,有门槛是因为它里边的概念多,用起来复杂,可是一旦你学会了Dagger2的使用,你一定会爱不释手的.与ButterKnife和AndroidAnnotatio ...
- [转帖]从零开始入门 K8s | 手把手带你理解 etcd
从零开始入门 K8s | 手把手带你理解 etcd https://zhuanlan.zhihu.com/p/96721097 导读:etcd 是用于共享配置和服务发现的分布式.一致性的 KV 存储系 ...
- 手摸手带你理解Vue的Watch原理
前言 watch 是由用户定义的数据监听,当监听的属性发生改变就会触发回调,这项配置在业务中是很常用.在面试时,也是必问知识点,一般会用作和 computed 进行比较. 那么本文就来带大家从源码理解 ...
- 大白话说Java泛型(二):深入理解通配符
文章首发于[博客园-陈树义],点击跳转到原文<大白话说Java泛型(二):深入理解通配符> 上篇文章<大白话说Java泛型(一):入门.原理.使用>,我们讲了泛型的产生缘由以及 ...
- 一个故事带你理解if __name__ == '__main__'
如果你刚刚接触python,相信会在看别人的程序的时候会遇到if __name__ == '__main__'酱紫的语法,如果当时没看懂现在也一知半解的话,看下去,本文可以帮你解决这个问题. 大家都知 ...
- JDK1.8源码逐字逐句带你理解LinkedHashMap底层
注意 我希望看这篇的文章的小伙伴如果没有了解过HashMap那么可以先看看我这篇文章:http://blog.csdn.net/u012403290/article/details/65442646, ...
- 手摸手带你理解Vue的Computed原理
前言 computed 在 Vue 中是很常用的属性配置,它能够随着依赖属性的变化而变化,为我们带来很大便利.那么本文就来带大家全面理解 computed 的内部原理以及工作流程. 在这之前,希望你能 ...
- Pthread 并发编程(二)——自底向上深入理解线程
Pthread 并发编程(二)--自底向上深入理解线程 前言 在本篇文章当中主要给大家介绍线程最基本的组成元素,以及在 pthread 当中给我们提供的一些线程的基本机制,因为很多语言的线程机制就是建 ...
- Android自己定义ViewGroup(二)——带悬停标题的ExpandableListView
项目里要加一个点击可收缩展开的列表,要求带悬停标题,详细效果例如以下图: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fon ...
随机推荐
- CreateObject("Wscript.Shell")用法
WScript.Shell是WshShell对象的ProgID,创建WshShell对象可以运行程序.操作注册表.创建快捷方式.访问系统文件夹.管理环境变量. 该对象有一个run方法. Run 方法创 ...
- linux下查看防火墙当前状态,开启关闭等
从配置菜单关闭防火墙是不起作用的,索性在安装的时候就不要装防火墙 查看防火墙状态: /etc/init.d/iptables status 暂时关闭防火墙: /etc/init.d/iptables ...
- 【HDOJ】1222 Wolf and Rabbit
最大公约数,辗转相除. #include <stdio.h> long long gcd(long long a, long long b) { if (a<b) return gc ...
- poj2723
把每对钥匙看做一个变量,那两个钥匙看做他的两个状态 每一个开门的要求就是一个条件(xi or xj) 很显然有了2sat的基本要素 2sat是一个判定性问题,而这题求最多能过几个门: 不难想到二分答案 ...
- FreeBSD方式安装 MAC OSX
首先你的电脑需要支持硬件虚拟化,可以用securable进行检测,如图所示即为支持,说明可以再你电脑的虚拟机里面安装苹果系统,如果有其中一项为NO,那么不好意思,你就没法安装了 2 其次你的电脑要提前 ...
- NuGet -- 使用控制台管理程序包
为什么要使用控制台管理程序包而不使用程序包管理窗口?原因大家都懂,生活压力这么大,一切都只是为了装一波.开个玩笑,当然不只是此原因,在有些情况下,有些操作使用程序包管理窗口不能达到目的,只能使用控制台 ...
- wildfly-9.0.2 web项目部署详细步骤
一.配置操作系统环境变量 JAVA_HOME = C:\Program Files (x86)\Java\jdk1.7.0_67 JBOSS_HOME = F:\server\wildfly-9.0. ...
- poj 1184 广搜进阶题
起初的想法果然就是一个6000000的状态的表示. 但是后面觉得还是太过于幼稚了. 可以看看网上的解释,其实就是先转换位置,然后再改变数字的大小. #include<iostream> # ...
- MVC Action 返回类型[转]
一. ASP.NET MVC 1.0 Result 几何? Action的返回值类型到底有几个?咱们来数数看. ASP.NET MVC 1.0 目前一共提供了以下十几种Action返回 ...
- Cocos2d-x获取随机数
计算机是无法产生真正的随机数的,都是伪随机.获取随机数的方式和算法多种多样,这里只给出一种方法,基于最新的C++11. 1 2 3 4 5 #include <random> std::u ...