Guice Account Scope
Google Guice 支持自定义Scope,当然通常情况下我们不需要自己实现Scope。RoboGuice作为Android的IOC容器,实现了基于当前Context的ContextScope。我们可以根据自己需求自定义Scope,实现一些特殊的需求。GitHub的Android客户端定义了一个AccountScope,实现了基于当前账户的上下文对象的注入。
自定义Scope
Scope接口
Scope接口本身很简单
scope方法需要实现,如何根据指定的Key,返回其对应的Provider。通常直接返回Provider
匿名实现类实例,在其实现方法get
方法中,具体实现如何scope对应的对象。
实现接口
接口实现参考官方示例
|
|
这个实现类实现了基于ThreadLocal,当前线程上下文的依赖注入。
定义Scope
上面只是实现了Scope接口,对于这个实现,需要进行定义其注解,并且绑定到注解
###定义注解
###绑定到注解
触发Scope
|
|
SimpleScope
需要先调用enter
进入Scope,然后即可进行创建,注入Scoped对象。这样的代码比较底层,通常在过滤器或者拦截器中实现Scope的enter和exit。
实现AccountScope
和上面实现的基于Thread的Scope类似,首先我们需要一个容器来维护所有Account的对象。这里可以用一个二维Map实现对应的保存,ThreadLocal保存当前线程所在的Account
|
|
然后需要实现基于Account上下文的注入时,将当前ThreadLocal的值设置为对应的Account对象,scope
方法的实现中即可根据当前线程上下文的Account找到对应的scopeMaps
的value值。
|
|
|
|
完整的实现可以参考。
使用AccountScope
Android平台下,需要使用到AccountScope的地方,比如说Account的账户数据同步;对API接口的访问。
Scope API接口的访问
对API接口的访问通常在AsyncLoader或者AsyncTask中进行,因此只对这两个类进行一定抽象可以实现Scope API接口。
在loadInBackground
中实现如下
然后即可根据当前Scope的Account对象,获取其Access Token(Android Account Framework),从而实现Scope对API接口的访问。
TIPS,这里也同时需要进入Context Scope,注入Context上下文环境中的对象。ContextScope
的实现使用了ThreadLocal,并且
Async是在其他Thread中执行的,所有必须重新enter,否则无法注入Context上下文中的对象。
集成Spring Social
Spring Social是以API Binding的方式实现API的访问。结合Roboguice的,理想的实现便是进行一次Binding,并将Binding对象注入guice容器中,然后在需要是要使用直接注入Binding对象即可。但是Spring Social绑定的过程中即需要access token,而上面对AccountScope的使用,只有调用AsyncLoader或者AsyncTask中才会进入AccountScope,获取其access token,这样只能每次调用的时候都进行一次API Binding。 所以可以对Spring Social进行扩展,使其Binding的时候不再依赖access token,而是依赖于Account的Provider对象。
Provider
Provider除了可以用于封装对象相对复杂的初始化,更重要的时可以实现Lazy loading。 即在初始化不直接注入对象本身,而是注入对应的Provider,然后在使用的再调用get
方法获取实例。
因为注入的Provider是个代理对象,最终会代理给直接Provider的对象返回结果,所以可以通过先bind一个空的Provider实现,然后进入对应的Scope后,注入实际的Provider。
|
|
扩展API Binding
利用Provider的机制,扩展API Binding,不再依赖access token,而是依赖Account的Provider,即可较为完美解决之前的问题。
RoboNoodlesServiceProvider覆盖getApi方法,返回依赖于Account的template
Template类重新配置Interceptor