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 | public class MyRectangle extends Rectangle{ |
和Android RoboGuice 使用指南(6):Instance Bindings 定义的含@Injector 标记的构造函数:
1 | public class MySquare extends MyRectangle { |
2 |
@Inject public MySquare( @Named ( "width" ) int width){ |
@ImplementedBy
该标记通知Injector某个类型的缺省实现,其功能和Linked Bindings 类似,例如:
1 | @ImplementedBy (PayPalCreditCardProcessor. class ) |
2 | public interface CreditCardProcessor { |
3 |
ChargeResult charge(String amount, CreditCard creditCard) |
4 |
throws UnreachableException; } |
和
1 | bind(CreditCardProcessor. class ) |
2 |
.to(PayPalCreditCardProcessor. class ); |
等效。 如果某个类型同时含有@ImplementedBy 和bind 定义,将优先使用bind 中的定义。
注: @ImplementedBy 定义了从Interface到实现的依赖,一般不建议使用。
@ProvidedBy
@ProvidedBy 通知Injector 某个类型使用那个缺省Provider来创建实例对象,例如:
1 | @ProvidedBy (DatabaseTransactionLogProvider. class ) |
2 | public interface TransactionLog { |
3 |
void logConnectException(UnreachableException e); |
4 |
void logChargeResult(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 | public class InMemoryTransactionLog implements TransactionLog { |
或者在Module中使用bind 语句:
1 | bind(TransactionLog. class ) |
2 |
.to(InMemoryTransactionLog. class ) |
如果使用@Provides,可以有:
2 | TransactionLog provideTransactionLog() { |
如果某个类型使用某个你不想使用的Scope标记,可以将其绑定到Scopes.NO_SCOPE取消这个Scope定义。
如果需要注入某个参数化类型,比如List<String>:
3 |
void setList(List<String> list) { |
可以使用TypeLiteral 来创建这个绑定。TypeLiteral 为一特殊类型可以用于表示参数化类型。
1 | @Override public void configure() { |
2 | bind( new TypeLiteral<List<String>>() {}) |
3 | .toInstance( new ArrayList<String>()); } |
或者使用@Provides 方法:
1 | @Provides List<String> providesListOfString() { |
2 |
return new 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 等,将在后面的文章详细说明。