Injector 通过检查bindings 定义来创建某个类型的实例对象。定义在Module中的绑定称为“明确声明绑定(Explicit bindings”。Injector 会首先使用带有Explicit Bindings为某个类型创建实例对象。 当但某个类型没有明确定义绑定时,Injector 试图构造“即时绑定(Just-in-time Bindings),JIT Bindings 也成为隐含绑定(implicit bindings).
Eligible Constructor
Injector 通过使用类的injectable constructor 来创建该类的实例对象。injectable constructor 可以为该类定义的public 不带参数的构造函数或是带有@Injector 标记的构造函数。
比如Android RoboGuice 使用指南(4):Linked Bindings中MyRectangle的无参数构造函数:
1 | publicclass MyRectangle extendsRectangle{ |
和Android RoboGuice 使用指南(6):Instance Bindings 定义的含@Injector 标记的构造函数:
1 | publicclass MySquare extendsMyRectangle { |
2 | @Injectpublic MySquare(@Named("width")intwidth){ |
@ImplementedBy
该标记通知Injector某个类型的缺省实现,其功能和Linked Bindings 类似,例如:
1 | @ImplementedBy(PayPalCreditCardProcessor.class) |
2 | publicinterface CreditCardProcessor { |
3 | ChargeResult charge(String amount, CreditCard creditCard) |
4 | throwsUnreachableException; } |
和
1 | bind(CreditCardProcessor.class) |
2 | .to(PayPalCreditCardProcessor.class); |
等效。 如果某个类型同时含有@ImplementedBy 和bind 定义,将优先使用bind 中的定义。
注: @ImplementedBy 定义了从Interface到实现的依赖,一般不建议使用。
@ProvidedBy
@ProvidedBy 通知Injector 某个类型使用那个缺省Provider来创建实例对象,例如:
1 | @ProvidedBy(DatabaseTransactionLogProvider.class) |
2 | publicinterface TransactionLog { |
3 | voidlogConnectException(UnreachableException e); |
4 | voidlogChargeResult(ChargeResult result); |
和下面Binding等效:
1 | bind(TransactionLog.class) |
2 | .toProvider(DatabaseTransactionLogProvider.class); |
和@ImplementedBy 一样,如果同时定义了@ProvidedBy和bind,模块中定义的bind 优先
缺省情况下,Guice每次都创建类的一个新的实例对象给需要该类实例的地方。可以使用Scopes来修改这个缺省行为,Scope允许在一定范围内重用类实例。Roboguice中常用的有两种:
- @Singleton 整个Application生命周期中使用同一实例对象
- @ContextScoped 同一个Context(如Activity)中共享某一实例对象。
使用Scope 的方法为使用相应的标记,如:
2 | publicclass InMemoryTransactionLog implementsTransactionLog { |
或者在Module中使用bind 语句:
1 | bind(TransactionLog.class) |
2 | .to(InMemoryTransactionLog.class) |
如果使用@Provides,可以有:
2 | TransactionLog provideTransactionLog() { |
如果某个类型使用某个你不想使用的Scope标记,可以将其绑定到Scopes.NO_SCOPE取消这个Scope定义。
如果需要注入某个参数化类型,比如List<String>:
3 | voidsetList(List<String> list) { |
可以使用TypeLiteral 来创建这个绑定。TypeLiteral 为一特殊类型可以用于表示参数化类型。
1 | @Overridepublic void configure() { |
2 | bind(newTypeLiteral<List<String>>() {}) |
3 | .toInstance(newArrayList<String>()); } |
或者使用@Provides 方法:
1 | @ProvidesList<String> providesListOfString() { |
2 | returnnew ArrayList<String>(); |
到目前为止,基本介绍了Google Guice 的用法,上面用法也适用于Java SE,Java EE平台,更详细的可以参见英文文档 ,后面接着介绍和Android平台相关的Dependency Injection (Roboguice)的用法。
前面在Android RoboGuice 使用指南(1):概述 对应Roboguice做了简要的介绍,之后介绍了Google Guice的基本用法,Roboguice是基本Android和Google Guice开发的适用于Android平台的Dependency Injection 开发包,下图为使用Roboguice开发应用的基本框图:
Android应用程序可以直接使用Google Guice来为普通类进行注入操作,而对和Android平台相关的类如Activity,Context,Service,View等可以使用Roboguice 进行注入操作。
在例Android RoboGuice 使用指南(2):第一个例子Hello World 介绍了使用RoboGuice开发的步骤,原先从Activity派生的类一般需要改成从RoboActivity派生,并添加从RoboApplication派生的类作为Application应用的Application类,详细的对应表如下:
RoboGuice支持的标记如下:
- @ContextScoped : 表示Scope为Context 范围 Android RoboGuice 使用指南(11): Scopes
- @InjectExtra : Intent的getExtra 的注入标记
- @InjectPreference: 注入Preference
- @InjectResource: 注入Resource,如drawable, icon 等
- @InjectView: 注入View
- @Inject: Guice标记,可以注入Android平台支持的各种服务,比如LocationManager等。
- @SharedPreferencesName: SharedPreferences 名称等
此外,RoboGuice还提供了简单的消息publish/subscribe 机制,以及可以支持Dependency Injection的RoboThread, RoboAsyncTask ,RoboLooperThread 等,将在后面的文章详细说明。