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 ...
随机推荐
- 一起学微软Power BI系列-官方文档-入门指南(6)Power BI与Excel
今天介绍了官方入门文档中有关PowerBI和Excel的知识.前几篇入门文档有点仓促,加上最近时间的研究,会有更多技巧性和入门型的文章或者视频发布,最后2篇入门文档将更加详细一点,因为部分文章进行简单 ...
- 创建 router 连通 subnet- 每天5分钟玩转 OpenStack(100)
上一节我们为 Neutron 虚拟路由器配置好了 L3 agent,今天将创建虚拟路由器“router_100_101”,打通 vlan100 和 vlan101. 打开操作菜单 Project -& ...
- EntityFramework 7.0之初探【基于VS 2015】(十)
前言 本篇作为EF 7.0的开篇也是Entity Framework目前系列末篇,因为关于EF 7.0学习资料实在是太少,我都是参考老外的资料花费了不少时间去研究去尝试同时也失败多次,个人觉得那是值得 ...
- 【续集】在 IIS 中部署 ASP.NET 5 应用程序遭遇的问题
dudu 的一篇博文:在 IIS 中部署 ASP.NET 5 应用程序遭遇的问题 针对 IIS 部署 ASP.NET 5 应用程序的问题,在上面博文中主要采用两种方式尝试: VS2015 的 Publ ...
- DevExpress控件安装、汉化使用教程
前言 DevExpress是一个庞大的控件库,也很是好用(没用过,听说),但是要收费. 网上关于DevExpress的教程满天飞,我找了一下午也没找到正确的安装.简单实用教程,还是自己摸索吧. 自己动 ...
- 相克军_Oracle体系_随堂笔记016-参数文件及数据库的启动和关闭
参数文件: spfile<SID>.ora 动态参数文件,是二进制文件,9i以后引入并建议使用 init<SID>.ora 静态参数文件,是文本文件 动态参数,部分 ...
- 小白Linux入门 四
http://edu.51cto.com/lesson/id-11372.html 28了 文件管理类命令 目录: mkdir mkdir /tmp/x mkdir -p /tmp/a/b -pv b ...
- Django admin 权威指南(一)
版本: Django 1.10 此部分由官方文档<6.5.1 The Django admin site>翻译而来. 6.5.1.1 概览 默认情况下,使用startproject的时候, ...
- Python_Day_01(使用环境为Python3.0+)
Python 变量与赋值. Python在赋值时时不需要进行定义类型,可直接进行定义赋值. #直接赋值字符串格式 value = "Char" #直接赋值为数字 value = 1 ...
- [Q&A] VS 连接 SQLServer 时未找到或无法访问服务器
异常信息: 参考解决方法: 1:检查下面两处服务器名是否一致并正确 (VS上) (SQL Server 2008 R2上) 2:VS 在下图位置处对实例名称的设定对于该异常无影响 3:确认在服务中启动 ...