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 ...
随机推荐
- 准备 KVM 实验环境 - 每天5分钟玩转 OpenStack(3)
KVM 是 OpenStack 使用最广泛的 Hypervisor,本节介绍如何搭建 KVM 实验环境 安装 KVM 上一节说了,KVM 是 2 型虚拟化,是运行在操作系统之上的,所以我们先要装一个 ...
- ASP.NET MVC之视图生成URL(二)
前言 上一节我们讲述了MVC中从控制器到视图传递数据的四种方式,想必大家早已掌握了,那我们继续往下走. 话题 在MVC的Web应用程序中,我们经常会出现这样的操作,从一个视图跳转到另外一个视图,大部分 ...
- Web APi之消息处理管道(五)
前言 MVC有一套请求处理的机制,当然Web API也有自己的一套消息处理管道,该消息处理管道贯穿始终都是通过HttpMessageHandler来完成.我们知道请求信息存在 RequestMessa ...
- 构建自己的PHP框架--实现Model类(3)
在之前的博客中,我们实现并完善了Model类的findOne方法,下面我们来实现其中的其他方法. 先来看findAll方法,这个方法和findOne很相似. public static functio ...
- iOS UIWebView 拦截点击事件(双击缩放)
在平时的开发中,要使用到webview,但类似微信的webview在数据没有加载完成的时候 双击屏幕,webview不会缩放,其实实现这个功能很简单 代码是用swift写的 class YYSimpl ...
- 为SharePoint 站点添加通知
作为思想.内容的共享型产品,SharePoint 不出意外的成为其中最好用的产品之一,想想平时在公司中接到通知并了解通知内容是件很平常的事情,那让这种平常的事情进入到SharePoint中可以通过如下 ...
- PHP面试题目搜集
搜集这些题目是想在学习PHP方面知识有更感性的认识,单纯看书的话会很容易看后就忘记. 曾经看过数据结构.设计模式.HTTP等方面的书籍,但是基本看完后就是看完了,没有然后了,随着时间的推移,也就渐渐忘 ...
- Word基础
1.页面设置 默认大小A4,长宽比0.618 页面布局 2.字体设置 选择要设置的字体->右键->字体 3.选择性粘贴 4.段落设置 选择文字->右键->段落 5.表格 =SU ...
- 让 OpenAL 也支持 S16 Planar(辅以 FFmpeg)
正在制作某物品,现在做到音频部分了. 原本要采用 SDL2_mixer 的,不过实验结果表明其失真非常严重,还带有大量的电噪声.不知道是不是我打开的方式不对…… 一气之下去看 OpenAL,结果吃了闭 ...
- 关于Javascript作用域及作用域链的总结
本文是根据以下文章以及<Javascript高级程序设计(第三版)>第四章相关内容总结的. 1.Javascript作用域原理,地址:http://www.laruence.com/200 ...