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 ...
随机推荐
- Util应用程序框架公共操作类(二):数据类型转换公共操作类(源码篇)
上一篇介绍了数据类型转换的一些情况,可以看出,如果不进行封装,有可能导致比较混乱的代码.本文通过TDD方式把数据类型转换公共操作类开发出来,并提供源码下载. 我们在 应用程序框架实战十一:创建VS解决 ...
- Python学习第一弹——Python环境搭建
一.Python简介: Python,是一种面向对象.解释型计算机程序设计语言,由Guido van Rossum于1989年底发明,第一个公开发行版发行于1991年.Python语法简洁而清晰,具有 ...
- 一款开源免费跨浏览器的视频播放器--videojs使用介绍
最近项目中的视频功能,需要做到浏览器全兼容,所以之前用html5实现的视频功能就需要进行改造了.在网上翻了个遍,试来试去,在所有的视频播放器中,就数它最实际了.首先我们来看看它的优点: 1.它是开源免 ...
- C语言 第一章 C语言简介
一.C语言介绍 C是一种通用的编程语言,广泛用于系统软件与应用软件的开发.于1969年至1973年间,为了移植与开发UNIX操作系统,由丹尼斯·里奇与肯·汤普逊,以B语言为基础,在贝尔实验室设计.开发 ...
- 关于BFC不会被浮动元素遮盖的一些解释
简介 在清除浮动一文中提到BFC不会被浮动元素遮盖,并没有详细探究表现行为.规范中指出,在同一个BFC内,作为子元素的BFC的border-box不应该覆盖同为子元素的浮动元素的margin-box. ...
- ZOJ Problem Set - 1201 Inversion
题目:这道题目的意思让人猛地一读有点反应不过来,简单解释下: 给定序列A:a1,a2,a3....,an,如果i<j且ai>aj则(ai,aj)称为序列A的一个倒置. 之后引出了序列的倒置 ...
- DotNet常用排序算法总结
数据结构和算法对一个程序来说是至关重要的,现在介绍一下几种算法,在项目中较为常用的算法有:冒泡排序,简单选择排序,直接插入排序,希尔排序,堆排序,归并排序,快速排序等7中算法. 现在介绍选择排序算法, ...
- TP框架执行流程分许
1. index.php 入口文件 2. ThinkPHP/ThinkPHP.php 在php5.3版本以后 设置常量有两种方式: const name = value; 作用域根据当前命名空间决定 ...
- 【十大经典数据挖掘算法】CART
[十大经典数据挖掘算法]系列 C4.5 K-Means SVM Apriori EM PageRank AdaBoost kNN Naïve Bayes CART 1. 前言 分类与回归树(Class ...
- php中的M方法