经过前两篇的介绍,我们了解了如何使用RoboGuice方便的为我们注入需要的对象,这篇将着重说明原理。

一.Guice与RoboGuice

Guise是Google开发的一个轻量级的依赖注入框架,主要针对Java使用的。

RoboGuice是基于Guice库开发,目的为Android提供一套简单易用的依赖注入框架。

上两篇中所提到的POJO注入,说白了就是对象注入,大部分方法都是Guice框架中的。RoboGuice主要在视图注入及Android个性化的注入上下功夫。

二.RoboGuice注入对象

就算没用过RoboGuice,但是大家也都听过,RoboGuice是通过反射来实现注入的。

为了了解实现的原理,我们先看下RoboActivity的代码。

其中eventManager初始化方式使用的就是之前提过的RoboGuice.getInjector(),其内部提供了各种事件的注册,反注册,分发等等功能。

public class RoboActivity extends Activity implements RoboContext {
protected EventManager eventManager;
protected HashMap<Key<?>,Object> scopedObjects = new HashMap<Key<?>, Object>(); @Inject ContentViewListener ignored; // BUG find a better place to put this
private Stopwatch stopwatch; @Override
protected void onCreate(Bundle savedInstanceState) {
stopwatch = new Stopwatch();
final RoboInjector injector = RoboGuice.getInjector(this);
stopwatch.resetAndLog("RoboActivity creation of injector");
eventManager = injector.getInstance(EventManager.class);
stopwatch.resetAndLog("RoboActivity creation of eventmanager");
injector.injectMembersWithoutViews(this);
stopwatch.resetAndLog("RoboActivity inject members without views");
super.onCreate(savedInstanceState);
stopwatch.resetAndLog("RoboActivity super onCreate");
eventManager.fire(new OnCreateEvent<Activity>(this,savedInstanceState));
stopwatch.resetAndLog("RoboActivity fire event");
}
}

其次注意到被注入的ContentViewListener,这就是为了实现在Activity上的ContentView的注解,这里的方法是

@ContextSingleton
public class ContentViewListener {
@Inject protected Activity activity; public void optionallySetContentView( @Observes OnCreateEvent<?> ignored ) {
Class<?> c = activity.getClass();
while( c != Context.class ) {
final ContentView annotation = c.getAnnotation(ContentView.class);
if( annotation!=null ) {
activity.setContentView(annotation.value());
return;
}
c = c.getSuperclass();
}
}
}

这里观察的是OnCreate的事件,事件的分发代码在OnCreate方法中,实现了setContentView的方法。

onCreate方法简化后如下。可以发现inject对象的时机是在super的onCreate之前的,

@Override
protected void onCreate(Bundle savedInstanceState) {
final RoboInjector injector = RoboGuice.getInjector(this);
eventManager = injector.getInstance(EventManager.class);
injector.injectMembersWithoutViews(this);
super.onCreate(savedInstanceState);
eventManager.fire(new OnCreateEvent<Activity>(this,savedInstanceState));
}

RoboInjector其实是RoboGuice内部的一个Guice Injector,大部分注入工作交给了Guice。

反射注入这一块就不深入讨论了,下面贴出了Guice的部分代码。

private static void computeInjectableMembers(TypeLiteral<?> type, boolean statics, Errors errors, InjectionPoint.InjectableMembers injectableMembers, InjectionPoint.OverrideIndex overrideIndex, HierarchyTraversalFilter filter) {
Class rawType = type.getRawType();
if(isWorthScanning(filter, rawType)) {
Class parentRawType = rawType.getSuperclass();
if(isWorthScanning(filter, parentRawType)) {
computeInjectableMembers(type.getSupertype(parentRawType), statics, errors, injectableMembers, overrideIndex, filter);
overrideIndex.position = InjectionPoint.Position.MIDDLE;
} else {
overrideIndex.position = InjectionPoint.Position.TOP;
} Set allFields = filter.getAllFields(Inject.class.getName(), rawType);
if(allFields != null) {
Iterator allMethods = allFields.iterator(); while(allMethods.hasNext()) {
Field i$ = (Field)allMethods.next();
if(Modifier.isStatic(i$.getModifiers()) == statics) {
Annotation method = getAtInject(i$);
if(method != null) {
InjectionPoint.InjectableField atInject = new InjectionPoint.InjectableField(type, i$, method);
if(atInject.jsr330 && Modifier.isFinal(i$.getModifiers())) {
errors.cannotInjectFinalField(i$);
} injectableMembers.add(atInject);
}
}
}
} Set allMethods1 = filter.getAllMethods(Inject.class.getName(), rawType);
if(allMethods1 != null) {
Iterator i$1 = allMethods1.iterator(); while(true) {
while(true) {
while(true) {
Method method1;
do {
if(!i$1.hasNext()) {
return;
} method1 = (Method)i$1.next();
} while(!isEligibleForInjection(method1, statics)); Annotation atInject1 = getAtInject(method1);
if(atInject1 != null) {
InjectionPoint.InjectableMethod removed2 = new InjectionPoint.InjectableMethod(type, method1, atInject1);
if(!checkForMisplacedBindingAnnotations(method1, errors) && isValidMethod(removed2, errors)) {
if(statics) {
injectableMembers.add(removed2);
} else {
overrideIndex.removeIfOverriddenBy(method1, true, removed2);
overrideIndex.add(removed2);
}
} else {
boolean removed1 = overrideIndex.removeIfOverriddenBy(method1, false, removed2);
if(removed1) {
logger.log(Level.WARNING, "Method: {0} is not a valid injectable method (because it either has misplaced binding annotations or specifies type parameters) but is overriding a method that is valid. Because it is not valid, the method will not be injected. To fix this, make the method a valid injectable method.", method1);
}
}
} else {
boolean removed = overrideIndex.removeIfOverriddenBy(method1, false, (InjectionPoint.InjectableMethod)null);
if(removed) {
logger.log(Level.WARNING, "Method: {0} is not annotated with @Inject but is overriding a method that is annotated with @javax.inject.Inject. Because it is not annotated with @Inject, the method will not be injected. To fix this, annotate the method with @Inject.", method1);
}
}
}
}
}
}
}
}

三.总结

这三篇过来,依赖注入给我们带来了什么?

解耦。

当我们在一个对象中,不需要关心它所依赖的成员如何初始化,只关心用来使用或获取属性,依赖注入为我们实现了解耦。

再就是RoboGuice的贴心,将Android基本组件考虑在内,为我们实现了很多注入,减少了我们调用系统服务或组件的代码,再就是RoboGuice考虑到了Android生命周期的特殊问题,将注入的成员对象生命周期保持与Context生命周期一致。

再说说反射,尽管RoboGuice强调,使用roboblender会优化很大一部分注解性能,但是反射对于移动端设备参差不齐的配置,还是让人有一点点担心,如果项目足够大,且使用了大量的注解及注入,那么性能一定是有影响的。

最后,RoboGuice确实是一个值得使用的框架,使用简单、上手较快、能实现模块解耦。光凭这几点优点便足以打动人心。

RoboGuice 3.0 (三)总结篇的更多相关文章

  1. RoboGuice 3.0 (一)入坑篇

    RoboGuice是什么? 一个Android上的依赖注入框架. 依赖注入是什么? 从字面理解,这个框架做了两件事情,第一是去除依赖,第二是注入依赖.简单理解就是,将对象的初始化委托给一个容器控制器, ...

  2. Aurora 8B/10B、PCIe 2.0、SRIO 2.0三种协议比较

    在高性能雷达信号处理机研制中,高速串行总线正逐步取代并行总线.业界广泛使用的Xilinx公司Virtex-6系列FPGA支持多种高速串行通信协议,本文针对其中较为常用的Aurora 8B/10B和PC ...

  3. Delphi 泛型(三十篇)

    Delphi 泛型(三十篇)http://www.cnblogs.com/jxgxy/category/216671.html

  4. RoboGuice 3.0 (二)进阶篇

    上篇介绍了RoboGuice的接入及基本使用,其中涉及到了一个@Singleton和@ContextSingleton的注解,这些都是作用域的注解,这篇我们先说明有关作用域的问题. 一.作用域 Sco ...

  5. JavaScript 面向对象(三) —— 高级篇

    JavaScript 面向对象(一) —— 基础篇 JavaScript 面向对象(二) —— 案例篇 一.json方式的面向对象 首先要知道,js中出现的东西都能够放到json中.关于json数据格 ...

  6. C#的变迁史 - C# 4.0 之多线程篇

    在.NET 4.0中,并行计算与多线程得到了一定程度的加强,这主要体现在并行对象Parallel,多线程Task,与PLinq.这里对这些相关的特性一起总结一下. 使用Thread方式的线程无疑是比较 ...

  7. 读懂IL代码就这么简单(三)完结篇

    一 前言 写了两篇关于IL指令相关的文章,分别把值类型与引用类型在 堆与栈上的操作区别详细的写了一遍 这第三篇也是最后一篇,之所以到第三篇就结束了,是因为以我现在的层次,能理解到的都写完了,而且个人认 ...

  8. ios -- 教你如何轻松学习Swift语法(三) 完结篇

    前言:swift语法基础篇(二)来了,想学习swift的朋友可以拿去参考哦,有兴趣可以相互探讨,共同学习哦.      一.自动引用计数   1.自动引用计数工作机制      1.1 swift和o ...

  9. Android UI开发第三十三篇——Navigation Drawer For Android API 7

    Creating a Navigation Drawer中使用的Navigation Drawer的android:minSdkVersion="14",现在Android API ...

随机推荐

  1. C# PPT 为形状设置三维效果

    在PPT中,形状是非常重要的元素.3-D形状,立体多元,给人耳目一新的感觉.在幻灯片中添加3-D效果形状,必然会为PPT的整体效果增色不少.为形状设置三维格式时,可设置棱台,轮廓线,表面效果等. 本篇 ...

  2. Oracle在线重定义DBMS_REDEFINITION 普通表—>分区表

    实验环境:RHEL 6.4 + Oracle 11.2.0.3实验:在线重定义 普通表 为 分区表,包括主键对应的索引都改造为分区索引. 1,构造普通表t_objects conn test1/tes ...

  3. JS打印对象的方法&将Object转换为String的函数

    1.有时候需要把对象中的字段属性打印出来,下面用JS实现输出对象: function writeObj(obj) { var description = ""; for (var ...

  4. Azure Application Gateway (4) 设置URL路由 - PowerShell

    <Windows Azure Platform 系列文章目录> 本文将介绍如果使用Azure PowerShell,创建Azure Application Gateway URL Rout ...

  5. 代码的坏味道(3)——基本类型偏执(Primitive Obsession)

    坏味道--基本类型偏执(Primitive Obsession) 特征 使用基本类型而不是小对象来实现简单任务(例如货币.范围.电话号码字符串等). 使用常量编码信息(例如一个用于引用管理员权限的常量 ...

  6. SQL Server 2016里的sys.dm_exec_input_buffer

    在你的DBA职业里,你们谁有用过DBCC INPUTBUFFER命令,来获得已经提交到SQL Server特定会话的最后SQL语句?请举手!大家都用过! 我们都知道DBCC命令有点尴尬,因为你不能在T ...

  7. [开源ORM] SqliteSugar 3.x .net Core版本成功上线

    SqliteSqlSugar 3.X API 作为支持.NET CORE 为数不多的ORM之一,除了具有优越的性能外,还拥有强大的功能,不只是满足你的增,删,查和改.实质上拥有更多你想像不到的功能,当 ...

  8. 4年,如何从草根成长成为CTO-(第一篇)

    茫然的求索 那一年,刚好经济危机,毕业了.经过了很长时间的“网上海投”而杳无音讯之后,终于发现“经济危机真的和自己有点关系了” ,曾经以为经济危机和自己巴刚子打不着. 拿着简历,开始到处去跑招聘市场, ...

  9. oracle实用sql之将逗号分割的字符串分割多个列

    select regexp_substr('a,b,c,','[^,]+',1,rownum) from dual connect by rownum<=length(regexp_replac ...

  10. 使用T4模板合并js文件

    不知道该怎么表达,或许直接贴图贴代码更好 前因:在第一个使用angularjs的项目中我将所有的controller写到一个文件里面,深知维护起来那滋味,所以再次使用angularjs的时候,我便把所 ...