经过前两篇的介绍,我们了解了如何使用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确实是一个值得使用的框架,使用简单、上手较快、能实现模块解耦。光凭这几点优点便足以打动人心。