背景:

网上各路资料都是浅层次的使用说明,即使是作为供他人使用的接口说明也是不合格的,所以还是得看看源码看官方文档。

Guice产生的源头

通常我们的一个Service 依赖多个其他的模块A,B,C, D,在Service里初始化这些A,B,C,D呢?大家都知道,搞UT的时候最麻烦最恶心的地方就是要考虑如何去Mock掉这些依赖,所以这样当然不是很好的方式。
那么通过setter来将它们设置进来呢?你会看到在实例化Service前有一大坨的对依赖的初始化代码。而且这些过程可能比较容易出错,比如你写的库给别人使用,其中的某个服务有较多的依赖,那么即使你写的很好的doc,而别人在使用的时候,会痛苦,最严重的是会出错。

那么Guice的作用就是 将依赖的处理也给默默的做了,那么在实例化服务的时候将会非常的清爽。
下面是SomeServices服务,其有两个依赖Depends2,Depends1

public class SomeServices {Depends2 depends2;@InjectDepends1 depends1;@Injectpublic SomeServices( Depends2 depends2) {this.depends2 = depends2;}public void start() {depends2.start();depends1.start();}
}

实例化SomeServices时候,只有简单的一行。

SomeServices someServices = Guice.createInjector(new SomeServicesModule()).getInstance(SomeServices.class);

Bindings

借助注解@Inject就能够将依赖给解决掉?这背后是如何实现的呢?
通过注解@Inject我们只知道依赖模块的类类型,也许他还是抽象类,离真正的解决依赖还有一段距离,那么就是通过Binding把这个差距给“连接”起来。

它在哪里实现

创建一个继承自AbstractModule的子类,然后实现configure方法。
Guice使用EDSL语言来使得创建bindings更简单可读性更好,
比如 bind ….to..
见:https://github.com/google/guice/wiki/Bindings
那么可以理解Bindings (实质就是对configure方法的实现过程)就是生成相应Injecter的一个配置。

那么RoboGuice又是?

RoboGuice 是Guice的扩展,增加了Android的支持。
从头说起,Guice跟Android平台无关,如果我们想使用一个fragment,他里面也是有很多依赖,依赖外界资源,依赖其他服务,依赖,依赖View组件,这堆依赖初始化也挺费事,直接用guice可以!但是你需要自己写Bindings, 比如@Inject Button btn;
那么RoboGuice就是帮你将Android平台下的Bindings给写好了。这就是他存在的意义。

继承RoboFragment?

那为什么没有见Guice.createInjector.getInstance之流?而是继承个RoboFragment?那么进入到RoboFragment中看看就明白了,在onCreate中

final RoboInjector injector = RoboGuice.getInjector(this);
injector.injectMembersWithoutViews(this);

getInjector 根据上下文环境获取适合的Injector

Injector是如何获取到的。

似乎Guice 直接getInjector(this) 就拿到了injector,那么Module是在哪里声明的呢?没有看到Module,我们就无法知晓注入的具体实现。

    public static RoboInjector getInjector(Context context) {final Application application = (Application)context.getApplicationContext();return new ContextScopedRoboInjector(context, getBaseApplicationInjector(application), getViewListener(application));}

再看getBaseApplicationInjector

    protected static WeakHashMap<Application,Injector> injectors = new WeakHashMap<Application,Injector>();public static Injector getBaseApplicationInjector(Application application) {Injector rtrn = injectors.get(application);if( rtrn!=null )return rtrn;synchronized (RoboGuice.class) {rtrn = injectors.get(application);if( rtrn!=null )return rtrn;return setBaseApplicationInjector(application, DEFAULT_STAGE);}}

injectors类似一个Injector的缓存,初始的时候当然是为空的。所以再看setBaseApplicationInjector

 public static Injector setBaseApplicationInjector(Application application, Stage stage) {synchronized (RoboGuice.class) {int id = modulesResourceId;if (id == 0)id = application.getResources().getIdentifier("roboguice_modules", "array", application.getPackageName());final String[] moduleNames = id>0 ? application.getResources().getStringArray(id) : new String[]{};final ArrayList<Module> modules = new ArrayList<Module>();final DefaultRoboModule defaultRoboModule = newDefaultRoboModule(application);modules.add(defaultRoboModule);try {for (String name : moduleNames) {final Class<? extends Module> clazz = Class.forName(name).asSubclass(Module.class);try {modules.add(clazz.getDeclaredConstructor(Context.class).newInstance(application));} catch( NoSuchMethodException ignored ) {modules.add( clazz.newInstance() );}}} catch (Exception e) {throw new RuntimeException(e);}final Injector rtrn = setBaseApplicationInjector(application, stage, modules.toArray(new Module[modules.size()]));injectors.put(application,rtrn);return rtrn;}}

解析上面的代码可以了解到:
1.Guice会默认去读取代码中名为roboguice_modules的string array里面的值,该值存什么呢?存储的是自定义AbstractModule的类全名,胡根据反射机制来实例化该AbstractModule。

2.Guice自己默认的AbstractModule为DefaultRoboModule,如果想了解一下其注入的实现可看看。

然后调用injector的injectMembersWithoutViews方法,该方法主要就是注入非View的Java对象。

在onViewCreated中

RoboGuice.getInjector(getActionBarActivity()).injectViewMembers(this);

注:
所有对View的插入实现都在ViewMembersInjector中。

几个常用注解

注解名 意义
@InjectView(R.id.name)
@InjectResource(R.drawable.icon)
@Inject
@Singleton 我们想要使用单例模式(Singleton Pattern)来获取对象,即 One Instance in the application,你可以在实现类上使用 Singleton 注释去标记。
@ProvidedBy(AddProvider.class) 可以直接在接口声明处使用 ProvidedBy 注释来指定该接口的 Provider 类型
@ImplementedBy(SimpleAdd.class) 如果 Add 接口有多个实现类,但是我们希望 SimpleAdd 是 Add 的默认实现类
@InjectExtra (“Extra1” ) String extra1 ??

几个常用Bindings写法

类型 意义
binder.bind(Add.class).to(SimpleAdd.class)
bind(CityController.class).in(Singleton.class) 没有指明目标实现类,那么要求类CityController应该由@ImplementedBy或@ProvidedBy标注过(也就是间接的定义了目标实现类类型)
toProvider(new CategoryProvider()) 指出目标实现类的Provider
annotatedWith(Names.named(“deal”)) 在该接口声明的地方是否有注解Names(“deal”),一般当接口有多个实现类的时候,通过注解Names来标明最终是用哪个实现类实例化

指明目标实现类的方法

一.在configure方法中通过bind().to(Target.class);
二.创建实现Provider接口的类,并在configure方法中通过bind().toProvider(new TargetProvider());
三.在AbstractModule的子类中,编写方法,返回相应类型,并用注解@Provides标注该方法,和方法二类似。
四.在接口定义上以@ImplementedBy(SimpleAdd.class)或 @ProvidedBy(AddProvider.class)标注

其他

install

在一个Module中

protected void configure {install(new NetModule(application));
}

在官方文档上很简单的说明:

void install(Module module)
Uses the given module to configure more bindings.

在宿主Module中引入NetModule中定义的bindings,类似允许一种封装及扩展吧。

参考链接:

Guice guide

Google Guice 系列教程 - 基础实践

Introduction to Google Guice

RoboGuice guide

RoboGuice 解析相关推荐

  1. 【FastDev4Android框架开发】RecyclerView完全解析之下拉刷新与上拉加载SwipeRefreshLayout(三十一)...

    转载请标明出处: http://blog.csdn.net/developer_jiangqq/article/details/49992269 本文出自:[江清清的博客] (一).前言: [好消息] ...

  2. Android 开源项目android-open-project工具库解析之(一) 依赖注入,图片缓存,网络相关,数据库orm工具包,Android公共库...

    一.依赖注入DI 通过依赖注入降低View.服务.资源简化初始化.事件绑定等反复繁琐工作 AndroidAnnotations(Code Diet) android高速开发框架 项目地址:https: ...

  3. golang通过RSA算法生成token,go从配置文件中注入密钥文件,go从文件中读取密钥文件,go RSA算法下token生成与解析;go java token共用

    RSA算法 token生成与解析 本文演示两种方式,一种是把密钥文件放在配置文件中,一种是把密钥文件本身放入项目或者容器中. 下面两种的区别在于私钥公钥的初始化, init方法,需要哪种取哪种. 通过 ...

  4. List元素互换,List元素转换下标,Java Collections.swap()方法实例解析

    Java Collections.swap()方法解析 jdk源码: public static void swap(List<?> list, int i, int j) {// ins ...

  5. 条形码?二维码?生成、解析都在这里!

    二维码生成与解析 一.生成二维码 二.解析二维码 三.生成一维码 四.全部的代码 五.pom依赖 直接上代码: 一.生成二维码 public class demo {private static fi ...

  6. Go 学习笔记(82)— Go 第三方库之 viper(解析配置文件、热更新配置文件)

    1. viper 特点 viper 是一个完整的 Go应用程序的配置解决方案,它被设计为在应用程序中工作,并能处理所有类型的配置需求和格式.支持特性功能如下: 设置默认值 读取 JSON.TOML.Y ...

  7. Go 学习笔记(77)— Go 第三方库之 cronexpr(解析 crontab 表达式,定时任务)

    cronexpr 支持的比 Linux 自身的 crontab 更详细,可以精确到秒级别. ​ 1. 实现方式 cronexpr 表达式从前到后的顺序如下所示: 字段类型 是否为必须字段 允许的值 允 ...

  8. mybatis配置文件解析

    mybatis配置文件解析 mybatis核心配置文件`mybatis-config.xml文件. mybatis的配置文件包含了会深深影响mybatis行为的设置和属性信息. 能配置的内容: con ...

  9. 谷歌BERT预训练源码解析(二):模型构建

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/weixin_39470744/arti ...

最新文章

  1. 四十一、文件的物理结构(上)
  2. [游戏模版21] Win32 物理引擎 能量守恒
  3. 手写自己的MyBatis框架-这个框架需要解决什么问题?
  4. 乒乓球比赛 两个乒乓球队进行比赛,各出三人。甲队为a,b,c三人,乙队为x,y,z三人。已抽签决定比赛名单。有人向队员打听比赛的名单。a说他不和x比,c说他不和x,z比 请编程序找出三队赛手的名单。
  5. CAD转图片,怎么转换成PNG图片?
  6. 我曾做过陈士成,也做过孔乙己,还做过阿Q
  7. 如何在Mac上恢复未保存的word文档
  8. python语言书写格式_设置Python代码格式
  9. 数据挖掘:概念与技术笔记(一)引言
  10. 给图片添加文字(换行)水印
  11. Nide.js安装配置
  12. cocos2d-x 3.2 |飞机大战:碰撞与分数
  13. B - 阿克曼函数(记忆化搜索(啊呸))
  14. 报错解决:Reason: Failed to determine a suitable driver class
  15. (转)人在德国:芦笋季节话芦笋
  16. 微信小程序开发:调用百度文字识别API实现图文识别
  17. 微信公众平台流量主单日广告收入最高达5万元 羡煞偶们
  18. 新冠疫情可视化(7月11日,7月12日)
  19. 打卡小程序的实现思路
  20. 《汇编语言》第5章 [BX]和loop指令

热门文章

  1. 全球的weex资源都在这里
  2. ethereumjs/ethereumjs-vm-4-tests
  3. 第2章 S交换机管理平面安全
  4. Golang中time包
  5. HDFS块文件和存放目录的关系
  6. eclipse 中的 maven run configurations
  7. HDU-2732 Leapin' Lizards 最大流
  8. [转] linux IO
  9. [Swift]LeetCode2. 两数相加 | Add Two Numbers
  10. 微软柯塔娜(Cortana)的一句名言