RoboGuice 3.0 (二)进阶篇
上篇介绍了RoboGuice的接入及基本使用,其中涉及到了一个@Singleton和@ContextSingleton的注解,这些都是作用域的注解,这篇我们先说明有关作用域的问题。
一.作用域 Scope
Scope指的是作用域,指的就是注入的对象的生命周期,RoboGuice提供了默认的几个作用域:
- @Singleton,被标注@Singleton注解的对象生命周期将保持和Application一致,也就是和整个App的生命周期一致。
- @ContextSingleton,被标注@ContextSingleton注解的对象生命周期将保持和Context提供者一致,这里主要指的是是Activity中,RoboGuice在Activity中提供了默认的Context容器,使我们初始化Activity成员的时候使用了这个容器中的Context,虽然注解
我们先看下RoboGuice的官方文档对@ContextSingleton的说明。
To the opposite of singletons created via @Singleton, the singletons created via@ContextSingleton are tied to a Context lifecycle and are garbage collected when this context gets destroyed.
大致就是,和@Singleton注解不同,@ContextSingleton注解是与Context的生命周期绑定的,当Context被销毁时,这种单例会随Context回收而回收。
When you use the annotation @ContextSingleton, you create an Object that will not be garbage collected within a given Context lifecycle. It will be destroyed when the context itself is destroyed, but will remain in memory even if your context doesn't use it anymore. This annotation can still create memory leaks if you don't use it properly, for instance when using fragments.
也就是当我们使用@ContextSingleton时,虽然是随生命周期联动的,但是当我们不使用这个单例对象时(当Context还存在时),这个对象会一直存于内存中,一个很明显的例子就是Fragment,在Fragment中标注一个@ContextSingleton属性的成员,当Fragment被回收而Activity没被回收时(因为Fragment中Context是从依附的Activity中获取的),还是会造成内存泄露。
RoboGuice官方文档声称,我们会加入一个@FragmentScope来解决这个问题,但是并没有,那个issue被关闭了,这一点还是很迷的,目前也没看到什么好的解决办法,只有从代码层面规范。
二.对象绑定
这里的对象绑定指的是将一个接口或类绑定到一个子类、对象、或对象提供容器上。当我们注入这个接口或类时,默认会根据绑定的类别初始化这个接口的实现。
对象绑定需要定义module,并且注册module到manifast文件。
欲练神功,需要两步:
- Register modules in your AndroidManifest.xml file
- Create classes that extend AbstractModule
翻译成代码就是这样:
<application
android:allowBackup="true"
android:name=".GuiceApplication"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity"
android:label="@string/title_activity_main"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<meta-data android:name="roboguice.modules"
android:value="github.pedroneer.roboguice.GuiceModule" />
public class GuiceModule extends AbstractModule {
@Override
protected void configure() {
}
}
好了,然后举个栗子。
定义一个GsonProvider的接口,
public interface GsonProvider {
Gson get();
}
我们在另一个类中实现了这个接口。
public class GsonProviderImpl implements GsonProvider {
@Override
public Gson get() {
return new GsonBuilder().
serializeNulls().
create();
}
}
在module中绑定GsonProvider到GsonProviderImpl上。
public class GuiceModule extends AbstractModule {
@Override
protected void configure() {
bind(GsonProvider.class).to(GsonProviderImpl.class);
}
}
这样我们在Activity中就可以使用@Inject去注入GsonProvider了,RoboGuice在初始化这个接口时会使用GsonProviderImpl定义的实现。
@ContentView(R.layout.activity_main)
public class MainActivity extends RoboFragmentActivity {
@Inject
GsonProvider gsonProvider;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String demoString = gsonProvider.get().toJson("123");
}
}
这时候你就会问了:"那我直接注入这个GsonProviderImpl不就可以了,你这是多此一举!"。
RoboGuice还提供了另一种实现方法,可能写起来会更简单一些。
这种方法就是在Module中定义Providers,简单理解就是容器提供这个对象的初始化服务,当你你需要使用这个对象时,容器会帮你初始化好。
public class GuiceModule extends AbstractModule {
@Override
protected void configure() {
//bind(GsonProvider.class).to(GsonProviderImpl.class);
}
@Provides
Gson provideGson(){
return new GsonBuilder()
.serializeNulls().
create();
}
}
@ContentView(R.layout.activity_main)
public class MainActivity extends RoboFragmentActivity {
@Inject
Gson gson;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String demoString = gson.toJson("123");
}
}
这样也是可以实现的,是不是觉得写起来更舒服一些,代码量也少了很多。
三.绑定类型
当我们需要注入不同属性的对象时,会用到类型绑定。
还是上面注入Gson的例子。当我需要属性不同的Gson时,上面的代码就实现不了了,比如上面提到的serializeNulls,是用来指定Gson在序列化时是否需要将null序列化。
例如下面这个model:
@SuppressWarnings("unused")
public class CommitData {
private int commentNum;
private int goodNum;
private int badNum;
private CommentReply commentReply;
public int getCommentNum() {
return commentNum;
}
public void setCommentNum(int commentNum) {
this.commentNum = commentNum;
}
public int getGoodNum() {
return goodNum;
}
public void setGoodNum(int goodNum) {
this.goodNum = goodNum;
}
public int getBadNum() {
return badNum;
}
public void setBadNum(int badNum) {
this.badNum = badNum;
}
public CommentReply getCommentReply() {
return commentReply;
}
public void setCommentReply(CommentReply commentReply) {
this.commentReply = commentReply;
}
public static class CommentReply{
private String reply;
private String time;
public String getReply() {
return reply;
}
public void setReply(String reply) {
this.reply = reply;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
}
}
CommitData data = new CommitData();
data.setBadNum(20);
data.setCommentNum(30);
data.setGoodNum(49);
当我们不初始化CommentReply对象时,带serializeNulls属性的Gson对象和不带是有区别的:
- 注明serializeNulls:{"badNum":20,"commentNum":30,"commentReply":null,"goodNum":49}
- 不带serializeNulls:{"badNum":20,"commentNum":30,"goodNum":49}
为了实现上述功能,我们之前定义的provider是有问题的,RoboGuice提供了类型的概念,我们可以定义和选择初始化使用的类型。使用的就是@Named注解,使用方法如下,当注入时,注明@Named字段来标示需要使用哪种初始化方法。
public class GuiceModule extends AbstractModule {
@Override
protected void configure() {
//bind(GsonProvider.class).to(GsonProviderImpl.class);
}
@Provides
@Named("Serialize Nulls")
Gson provideGson(){
return new GsonBuilder()
.serializeNulls().
create();
}
@Provides
@Named("Custom")
Gson provideCustomGson(){
return new GsonBuilder().
create();
}
}
@ContentView(R.layout.activity_main)
public class MainActivity extends RoboFragmentActivity {
private static final String TAG = "MainActivity";
@Inject
@Named("Serialize Nulls")
Gson gson;
@Inject
@Named("Custom")
Gson customGson;
@SuppressLint("SetTextI18n")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
CommitData data = new CommitData();
data.setBadNum(20);
data.setCommentNum(30);
data.setGoodNum(49);
String demoString = gson.toJson(data);
Log.d(TAG, "onCreate: " + demoString);
demoString = customGson.toJson(data);
Log.d(TAG, "onCreate: " + demoString);
}
}
除了上面这种写法,我们还可以这样使用:效果是相同的。
public class GuiceModule extends AbstractModule {
@Override
protected void configure() {
bind(GsonProvider.class).annotatedWith(Names.named("Custom")).to(GsonProviderImpl.class);
bind(GsonProvider.class).annotatedWith(Names.named("Serialize Nulls")).to(GsonNotSNProviderImpl.class);
}
}
public class GsonProviderImpl implements GsonProvider {
@Override
public Gson get() {
return new GsonBuilder().
serializeNulls().
create();
}
}
public class GsonNotSNProviderImpl implements GsonProvider{
@Override
public Gson get() {
return new GsonBuilder().create();
}
}
除此之外,RoboGuice还提供手动绑定实现Provider方法的方式,代码如下。
public class GuiceModule extends AbstractModule {
@Override
protected void configure() {
bind(GsonProvider.class).annotatedWith(Names.named("Serialize Nulls")).to(GsonNotSNProviderImpl.class);
bind(GsonProvider.class).annotatedWith(Names.named("Custom")).toProvider(GsonImpl.class);
}
static class GsonImpl implements Provider<GsonProviderImpl>{
@Override
public GsonProviderImpl get() {
return new GsonProviderImpl();
}
}
}
@ContentView(R.layout.activity_main)
public class MainActivity extends RoboFragmentActivity {
private static final String TAG = "MainActivity";
@Inject
@Named("Serialize Nulls")
GsonProvider gson;
@Inject
@Named("Custom")
GsonProvider customGson;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
CommitData data = new CommitData();
data.setBadNum(20);
data.setCommentNum(30);
data.setGoodNum(49);
String demoString = gson.get().toJson(data);
Log.d(TAG, "onCreate: " + demoString);
demoString = customGson.get().toJson(data);
Log.d(TAG, "onCreate: " + demoString);
}
最后,还有一些比较小的点,比如Module可以存在默认的构造方法,传入的是Application,绑定时候的作用域、使用Provider注解的作用域(下图中in.(Singleton.class))等等。
public class GuiceModule extends AbstractModule {
private Application application;
public GuiceModule(Application application) {
this.application = application;
}
@Override
protected void configure() {
bind(GsonProvider.class).annotatedWith(Names.named("Serialize Nulls")).to(GsonNotSNProviderImpl.class);
bind(GsonProvider.class).annotatedWith(Names.named("Custom")).toProvider(GsonImpl.class).in(Singleton.class);
}
static class GsonImpl implements Provider<GsonProviderImpl>{
@Override
public GsonProviderImpl get() {
return new GsonProviderImpl();
}
}
}
四.其他常用方法
RoboGuice还提供了IntentExtra的获取,但是注意,如果标注@InjectExtra的value没有找到对应的数据,则app会crash,如果允许获取不到extra,则必须将optional = true。
除此之外,RoboGuice提供了直接获取图中对象的方法,如下的Gson对象获取。
@ContentView(R.layout.activity_second)
public class SecondActivity extends RoboFragmentActivity {
@InjectExtra(value = "pull", optional = true)
String pull;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Gson gson = RoboGuice.getInjector(this).getInstance(Gson.class);
String demoStr = gson.toJson(pull);
Ln.d(demoStr);
}
}
五.Events、Ln
RoboGuice提供了默认的观察者模式,我们可以接收Activity的生命周期事件。
Ln则是RoboGuice的log神器,使用比较方便。
@ContentView(R.layout.activity_main)
public class MainActivity extends RoboFragmentActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public void doSomethingOnResume(@Observes OnResumeEvent event) {
if (event.getActivity() != null) {
Ln.e("onResume");
}
}
}
03-03 18:40:20.053 12381-12381/github.pedroneer.roboguice E//MainActivity.java:72: main onResume
此外还可以自定义事件,可以在RoboGuice的Wiki查看,这里不赘述。
https://github.com/roboguice/roboguice/wiki/Using-Events-in-your-RoboGuice-application
RoboGuice 3.0 (二)进阶篇的更多相关文章
- Sass进阶之路,之二(进阶篇)
Sass之二(进阶篇) 1. 数据类型 1.1 Number 数字类型,小数类型,带有像素单位的数字类型,全部都属于Number类型 Number类型详情请点击这里,下面是小例子 1.$n1: 1.2 ...
- Dagger2 (二) 进阶篇
一.作用域Scope 之前了解RoboGuice的时候,我们知道它默认给我们提供了几个注解,ContextSingleton和Singleton,但是Dagger2更为灵活,只有javax包中提供的S ...
- Sass之二(进阶篇)
源码链接:http://pan.baidu.com/s/1o8M51hC 1. 数据类型 1.1 Number 数字类型,小数类型,带有像素单位的数字类型,全部都属于Number类型 Number类型 ...
- RoboGuice 3.0 (一)入坑篇
RoboGuice是什么? 一个Android上的依赖注入框架. 依赖注入是什么? 从字面理解,这个框架做了两件事情,第一是去除依赖,第二是注入依赖.简单理解就是,将对象的初始化委托给一个容器控制器, ...
- CocoaPods详解之(二)----进阶篇
CocoaPods详解之----进阶篇 作者:wangzz 原文地址:http://blog.csdn.net/wzzvictory/article/details/19178709 转载请注明出处 ...
- WPF 4 DataGrid 控件(进阶篇二)
原文:WPF 4 DataGrid 控件(进阶篇二) 上一篇<WPF 4 DataGrid 控件(进阶篇一)>中我们通过DataGridTemplateColumn 类自定义编辑 ...
- idea 插件的使用 进阶篇
CSDN 2016博客之星评选结果公布 [系列直播]零基础学习微信小程序! "我的2016"主题征文活动 博客的神秘功能 idea 插件的使用 进阶篇(个人收集 ...
- 2. web前端开发分享-css,js进阶篇
一,css进阶篇: 等css哪些事儿看了两三遍之后,需要对看过的知识综合应用,这时候需要大量的实践经验, 简单的想法:把qq首页全屏另存为jpg然后通过ps工具切图结合css转换成html,有无从下手 ...
- python 面向对象(进阶篇)
上一篇<Python 面向对象(初级篇)>文章介绍了面向对象基本知识: 面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用 类 是一个模板,模板中包装了多个“函数”供使 ...
- 最快让你上手ReactiveCocoa之进阶篇
前言 由于时间的问题,暂且只更新这么多了,后续还会持续更新本文<最快让你上手ReactiveCocoa之进阶篇>,目前只是简短的介绍了些RAC核心的一些方法,后续还需要加上MVVM+Rea ...
随机推荐
- 附录E 安装Kafka
E.1 安装Kafka E.1.1 下载Kafka Kafka是由LinkedIn设计的一个高吞吐量.分布式.基于发布订阅模式的消息系统,使用Scala编写,它以可水平扩展.可靠性.异步通信 ...
- 1Z0-053 争议题目解析481
1Z0-053 争议题目解析481 考试科目:1Z0-053 题库版本:V13.02 题库中原题为: 481.Which statement is true about a running sessi ...
- Java多线程学习笔记
进程:正在执行中的程序,其实是应用程序在内存中运行的那片空间.(只负责空间分配) 线程:进程中的一个执行单元,负责进程汇总的程序的运行,一个进程当中至少要有一个线程. 多线程:一个进程中时可以有多个线 ...
- jQuery-1.9.1源码分析系列(十) 事件系统——事件委托
jQuery的事件绑定有几个比较优秀的特点: 1. 可以绑定不限数量的处理函数 2. 事件可以委托到祖先节点,不必一定要绑到对应的节点,这样后添加的节点也照样能被处理. 3. 链式操作 下面主要分析事 ...
- jQuery-1.9.1源码分析系列(十四) 一些jQuery工具
为了给下一章分析动画处理做准备,先来看一下一些工具.其中队列工具在动画处理中被经常使用. jQuery.fn. queue(([ queueName ] [, newQueue ]) || ([ qu ...
- Game中的状态机
我相信大多数博友都会玩游戏. 玩游戏,牵涉到状态包含 登陆,正常,死亡,复活,下线, 在上面状态的基础上.同时包含 站立,走动,跑动,不可移动施法状态, 战斗状态, 通常这是三个不同的分组.也就说可以 ...
- 通过一个模拟程序让你明白ASP.NET MVC是如何运行的
ASP.NET MVC的路由系统通过对HTTP请求的解析得到表示Controller.Action和其他相关的数据,并以此为依据激活Controller对象,调用相应的Action方法,并将方法返回的 ...
- ASP.NET Core中间件(Middleware)实现WCF SOAP服务端解析
ASP.NET Core中间件(Middleware)进阶学习实现SOAP 解析. 本篇将介绍实现ASP.NET Core SOAP服务端解析,而不是ASP.NET Core整个WCF host. 因 ...
- ASP.NET Core 介绍和项目解读
标签: ASP.NETCore 1. 前言 2. ASP.NET Core 简介 2.1 什么是ASP.NET Core 2.2 ASP.NET Core的特点 2.3 ASP.NET Core 项目 ...
- WCF入门教程(五)配置文件
WCF入门教程(五)配置文件 服务协定以及实现写好后,需要将相关服务公布出去,就需要HOST来承载,供客户端来调用. 承载服务有两种方式,一种通过配置文件,一种通过代码进行配置.上一章已经介绍了代码方 ...