经过前两篇的介绍,我们了解了如何使用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. BAT及各大互联网公司2014前端笔试面试题--JavaScript篇

    很多面试题是我自己面试BAT亲身经历碰到的.整理分享出来希望更多的前端er共同进步吧,不仅适用于求职者,对于巩固复习js更是大有裨益. 而更多的题目是我一路以来收集的,也有往年的,答案不确保一定正确, ...

  2. IDDD 实现领域驱动设计-一个简单业务用例的回顾和理解

    上一篇:<IDDD 实现领域驱动设计-由贫血导致的失忆症> 这篇博文是对<实现领域驱动设计>第一章后半部分内容的理解. Domain Experts-领域专家 这节点内容是昨天 ...

  3. react-native 学习之Image篇

    /** * Sample React Native App * https://github.com/facebook/react-native */ 'use strict'; import Rea ...

  4. vue+node开发手机端h5页面开发遇到的坑

    项目进行中...随时更新 这里记录了一些手机端调试的方式 一 css 1.文字超过span宽度显示...(单行文字) .topWrap .introduce span { padding: 0 17p ...

  5. C#文件相同性判断

    在进行开发时,对文件进行上传和下载是较为普遍的行为,为了防止在文件操作过程中,出现同一文件多次操作,需要对文件进行相同性比较: 1.获取文件的绝对路径,针对window程序和web程序都可使用: // ...

  6. 【十大经典数据挖掘算法】kNN

    [十大经典数据挖掘算法]系列 C4.5 K-Means SVM Apriori EM PageRank AdaBoost kNN Naïve Bayes CART 1. 引言 顶级数据挖掘会议ICDM ...

  7. 利用js2image把代码压缩成圣诞树

    马上圣诞节了,作为一名程序猿,如何体现自己独特的过节风格,如何在朋友圈发一张专属自己的祝福照片我觉得很有必要,你们说是不是. 谈到圣诞节,话说程序猿和圣诞之间的关系还有这么一个笑话: Q:程序员为什么 ...

  8. entity framework 5 批量增删改效率优化

    对于数据的批量增删改最慢的就是操作一条就提交一次事务. 以下是对增删改操作的优化测试 同样的300条数据 批量新增只提交一次事务 用时:10673.5444ms 批量新增只提交一次事务并把contex ...

  9. cmd执行SQL语句

    首先新建txt文本,复制粘帖以下内容,保存为cmd执行SQL.bat.注意是bat文件 osql -S 服务器名称 -d 数据库 -U 登录名 -P 密码 -i 盘符:\文件夹\文件.sql

  10. 深度学习 - DL

    雷锋网 - 2016 | 人工智能在深度学习领域的前世今生(原文链接) Deep Learning - DL,深度学习是机器学习的一种. 深度学习最重要的作用:表示学习 深度学习实践的四个关键要素 计 ...