关于依赖注入
@H_404_5@通常博主开发项目时喜欢以Activity 、Service 等组件作为顶级层入口,辅以各类接口作为业务服务。Activity 主要负责维护界面相关的东西,及提供功能所需要的上下文环境,引入功能实现需要的接口。
这些接口的实例通过Roboguice进行注入。(当然你也可以完全不使用Roboguice,但还是建议保留接口注入的设计)。
关于Roboguice
项目地址:https://github.com/roboguice/roboguice.利用Roboguice可以较轻松的注入各种服务,它默认提供了各种android相关的注入如: injectView,injectResource 等。
遗憾的是这里将不对Roboguice的使用详细讲解。想了解 Roboguice 的读者可以查看官网的Wiki 或参考:http://www.imobilebbs.com/wordpress/archives/2480
下载需要的包
项目创建
基本功能
@H_404_5@项目仅包含一个Activity,界面上包含一个TextView和Button.点击Button 可查看当前时间。@H_404_5@
@H_403_52@@H_404_5@通常我喜欢把数据相关的模块(db、sharepreferene、net、cache等)归类到Repository中,对上层而言就形成一个数据来源接口。@H_404_5@
注意:没有哪一种设计是万能,需要根据最实际的情况,不断的进行权衡,最终选择较合适的系统设计,并且要做好睡着系统的成长需要变更设计的准备@H_404_5@。@H_404_5@
例如有的android程序比较简单,就完全不需要 IService 服务层。@H_404_5@
项目包结构
使用静态类的实现方式
1@H_404_5@@H_404_5@public@H_404_5@@H_404_5@class@H_404_5@AndroidTimeRead{@H_404_5@
3@H_404_5@ public@H_404_5@ static@H_404_5@TimeviewmodelshowTime(){
4@H_404_5@Timeviewmodelmodel= new@H_404_5@Timeviewmodel();
5@H_404_5@model.setTime(String.valueOf(System.currentTimeMillis()));
6@H_404_5@ return@H_404_5@model;
7@H_404_5@}
8@H_404_5@
9@H_404_5@}
10@H_404_5@
11@H_404_5@ public@H_404_5@ class@H_404_5@MainActivity extends@H_404_5@Activity{
12@H_404_5@
13@H_404_5@ private@H_404_5@TextViewtxtShowTime;
14@H_404_5@ private@H_404_5@ButtonbtnShow;
15@H_404_5@
16@H_404_5@@Override
17@H_404_5@ protected@H_404_5@ void@H_404_5@onCreate(BundlesavedInstanceState){
18@H_404_5@ super@H_404_5@.onCreate(savedInstanceState);
19@H_404_5@setContentView(R.layout.activity_main);
20@H_404_5@
21@H_404_5@txtShowTime=(TextView)findViewById(R.id.txtShowTime);
22@H_404_5@btnShow=(Button)findViewById(R.id.btnShow);
23@H_404_5@btnShow.setOnClickListener( new@H_404_5@View.OnClickListener(){
24@H_404_5@
25@H_404_5@@Override
26@H_404_5@ public@H_404_5@ void@H_404_5@onClick(Viewv){
27@H_404_5@Timeviewmodelviewmodel=AndroidTimeRead.showTime();
28@H_404_5@txtShowTime.setText(viewmodel.getTime());
29@H_404_5@}
30@H_404_5@});
31@H_404_5@
32@H_404_5@}
33@H_404_5@
34@H_404_5@}
另一个问题是:当你想对MainActivity 进行单元测试,你会发现非常困难,AndroidTimeRead 必须被包含进来,如果它还引用了其他的组件(如Db 或 net),那么这些组件也必须包含入内。@H_404_5@静态类型因为一直在内存中,如果它引用了其他类型,则被引用的对象CG无法回收。@H_404_5@
改进
2@H_404_5@
3@H_404_5@ private@H_404_5@ static@H_404_5@ class@H_404_5@InstaceHolder{
4@H_404_5@ public@H_404_5@ static@H_404_5@AndroidTimeReadinstance= new@H_404_5@AndroidTimeRead();
5@H_404_5@}
6@H_404_5@
7@H_404_5@ public@H_404_5@ static@H_404_5@AndroidTimeReadgetInstance(){
8@H_404_5@ return@H_404_5@InstaceHolder.instance;
9@H_404_5@}
10@H_404_5@
11@H_404_5@ private@H_404_5@AndroidTimeRead(){}
12@H_404_5@
13@H_404_5@ public@H_404_5@TimeviewmodelshowTime(){
14@H_404_5@Timeviewmodelmodel= new@H_404_5@Timeviewmodel();
15@H_404_5@model.setTime(String.valueOf(System.currentTimeMillis()));
16@H_404_5@ return@H_404_5@model;
17@H_404_5@}
18@H_404_5@
19@H_404_5@}
1@H_404_5@Timeviewmodelviewmodel=AndroidTimeRead.getInstance().showTime();@H_404_5@调用修改@H_404_5@
这里去掉了静态的方式,可是却没有解除直接依赖实现的问题。@H_404_5@
关注行为
2@H_404_5@TimeviewmodelshowTime(); @H_404_5@
1@H_404_5@@H_404_5@private@H_404_5@ITimeServicetimeService;@H_404_5@
@H_404_5@ 3@H_404_5@ @H_404_5@ public@H_404_5@ void@H_404_5@setTimeService(ITimeServicetimeService){
4@H_404_5@ this@H_404_5@.timeService=timeService;
5@H_404_5@}
6@H_404_5@
7@H_404_5@@Override
8@H_404_5@ protected@H_404_5@ void@H_404_5@onCreate(BundlesavedInstanceState){
9@H_404_5@ super@H_404_5@.onCreate(savedInstanceState);
10@H_404_5@setContentView(R.layout.activity_main);
11@H_404_5@
12@H_404_5@txtShowTime=(TextView)findViewById(R.id.txtShowTime);
13@H_404_5@btnShow=(Button)findViewById(R.id.btnShow);
14@H_404_5@btnShow.setOnClickListener( new@H_404_5@View.OnClickListener(){
15@H_404_5@
16@H_404_5@@Override
17@H_404_5@ public@H_404_5@ void@H_404_5@onClick(Viewv){
18@H_404_5@Timeviewmodelviewmodel=timeService.showTime();
19@H_404_5@txtShowTime.setText(viewmodel.getTime());
20@H_404_5@}
21@H_404_5@});
22@H_404_5@
23@H_404_5@}
遗憾的是上面的程序不能正常运行,ITimeService 没有实例化。我们虽然提供了注入点,但是Activity 的生命周期由系统接管,我们无法直接使用。@H_404_5@
事实上当你使用Roboguice 时也是需要继承自其提供的RoboActivity。@H_404_5@
完成业务代码
@H_404_5@在引入Roboguice 前先完成Demo的结构。添加ITimeRepository 和对应的实现,并让AndroidTimeRead 依赖 ITimeRepository。@H_404_5@
private@H_404_5@ITimeRepositoryrep;
public@H_404_5@AndroidTimeRead(ITimeRepositoryrep){
this@H_404_5@.rep=rep;
}
public@H_404_5@TimeviewmodelshowTime(){
Timeviewmodelmodel= new@H_404_5@Timeviewmodel();
model.setTime("现在的时间是"+String.valueOf(rep.query()));
return@H_404_5@model;
}
}
引入Roboguice 应该放在哪里?
命名一个Infrastructure包,将需要的基础设施放置在此。@H_404_5@
引入RoboActivity
2@H_404_5@
3@H_404_5@@InjectView(R.id.txtShowTime)
4@H_404_5@ private@H_404_5@TextViewtxtShowTime;
5@H_404_5@@InjectView(R.id.btnShow)
6@H_404_5@ private@H_404_5@ButtonbtnShow;
7@H_404_5@
8@H_404_5@@Inject
9@H_404_5@ private@H_404_5@ITimeServicetimeService;
10@H_404_5@ //@H_404_5@ 提供注入点@H_404_5@
@H_404_5@ 11@H_404_5@ @H_404_5@ public@H_404_5@ void@H_404_5@setTimeService(ITimeServicetimeService){
12@H_404_5@ this@H_404_5@.timeService=timeService;
13@H_404_5@}
14@H_404_5@
15@H_404_5@@Override
16@H_404_5@ protected@H_404_5@ void@H_404_5@onCreate(BundlesavedInstanceState){
17@H_404_5@ super@H_404_5@.onCreate(savedInstanceState);
18@H_404_5@setContentView(R.layout.activity_main);
19@H_404_5@
20@H_404_5@btnShow.setOnClickListener( new@H_404_5@View.OnClickListener(){
21@H_404_5@
22@H_404_5@@Override
23@H_404_5@ public@H_404_5@ void@H_404_5@onClick(Viewv){
24@H_404_5@Timeviewmodelviewmodel=timeService.showTime();
25@H_404_5@txtShowTime.setText(viewmodel.getTime());
26@H_404_5@}
27@H_404_5@});
28@H_404_5@
29@H_404_5@}
2@H_404_5@
3@H_404_5@@Override
4@H_404_5@ public@H_404_5@ void@H_404_5@onCreate(){
5@H_404_5@ super@H_404_5@.onCreate();
6@H_404_5@RoboGuice.setBaseApplicationInjector( this@H_404_5@,RoboGuice.DEFAULT_STAGE,
7@H_404_5@RoboGuice.newDefaultRoboModule( this@H_404_5@),new@H_404_5@TimeModule());
8@H_404_5@}
9@H_404_5@}
2@H_404_5@
3@H_404_5@@Override
4@H_404_5@ public@H_404_5@ void@H_404_5@configure(Binderbinder){
5@H_404_5@ //@H_404_5@ 顺序无关,在具体的Activity中被创建@H_404_5@
@H_404_5@ 6@H_404_5@ @H_404_5@binder
7@H_404_5@.bind(ITimeService. class@H_404_5@)
8@H_404_5@.to(AndroidTimeRead. class@H_404_5@);
9@H_404_5@ //@H_404_5@ .in(Singleton.class);@H_404_5@ //@H_404_5@ 单件@H_404_5@
@H_404_5@ 10@H_404_5@ @H_404_5@
11@H_404_5@binder.bind(ITimeRepository. class@H_404_5@)
12@H_404_5@.to(TimeRepository. class@H_404_5@);
13@H_404_5@
14@H_404_5@}
15@H_404_5@
16@H_404_5@}
2@H_404_5@
3@H_404_5@@Inject
4@H_404_5@ITimeRepositoryrep;
5@H_404_5@
6@H_404_5@@Override
7@H_404_5@ public@H_404_5@AndroidTimeReadget(){
8@H_404_5@
9@H_404_5@ return@H_404_5@ new@H_404_5@AndroidTimeRead(rep);
10@H_404_5@}
11@H_404_5@
12@H_404_5@}
3@H_404_5@ //@H_404_5@ 顺序无关,在具体的Activity中被创建@H_404_5@
@H_404_5@ 4@H_404_5@ @H_404_5@binder
5@H_404_5@.bind(ITimeService. class@H_404_5@)
6@H_404_5@.to(AndroidTimeRead. class@H_404_5@);
7@H_404_5@ //@H_404_5@ .in(Singleton.class);@H_404_5@ //@H_404_5@ 单件@H_404_5@
@H_404_5@ 8@H_404_5@ @H_404_5@
9@H_404_5@binder.bind(ITimeRepository. class@H_404_5@)
10@H_404_5@.to(TimeRepository. class@H_404_5@);
11@H_404_5@
12@H_404_5@binder.bind(AndroidTimeRead. class@H_404_5@)
13@H_404_5@.toProvider(AndroidTimeReadProvider. class@H_404_5@);
14@H_404_5@
15@H_404_5@}
引入注入框架需要的思考:
3、其他可选择的框架如 dagger @H_404_5@