关于依赖注入
通常博主开发项目时喜欢以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
下载需要的包
项目创建
基本功能
项目仅包含一个Activity,界面上包含一个TextView和Button.点击Button 可查看当前时间。
通常我喜欢把数据相关的模块(db、sharepreferene、net、cache等)归类到Repository中,对上层而言就形成一个数据来源接口。
注意:没有哪一种设计是万能,需要根据最实际的情况,不断的进行权衡,最终选择较合适的系统设计,并且要做好睡着系统的成长需要变更设计的准备。
例如有的android程序比较简单,就完全不需要 IService 服务层。
项目包结构
使用静态类的实现方式
1publicclassAndroidTimeRead{
3 public staticTimeviewmodelshowTime(){
4Timeviewmodelmodel= newTimeviewmodel();
5model.setTime(String.valueOf(System.currentTimeMillis()));
6 returnmodel;
7}
8
9}
10
11 public classMainActivity extendsActivity{
12
13 privateTextViewtxtShowTime;
14 privateButtonbtnShow;
15
16@Override
17 protected voidonCreate(BundlesavedInstanceState){
18 super.onCreate(savedInstanceState);
19setContentView(R.layout.activity_main);
20
21txtShowTime=(TextView)findViewById(R.id.txtShowTime);
22btnShow=(Button)findViewById(R.id.btnShow);
23btnShow.setOnClickListener( newView.OnClickListener(){
24
25@Override
26 public voidonClick(Viewv){
27Timeviewmodelviewmodel=AndroidTimeRead.showTime();
28txtShowTime.setText(viewmodel.getTime());
29}
30});
31
32}
33
34}
另一个问题是:当你想对MainActivity 进行单元测试,你会发现非常困难,AndroidTimeRead 必须被包含进来,如果它还引用了其他的组件(如Db 或 net),那么这些组件也必须包含入内。静态类型因为一直在内存中,如果它引用了其他类型,则被引用的对象CG无法回收。
改进
2
3 private static classInstaceHolder{
4 public staticAndroidTimeReadinstance= newAndroidTimeRead();
5}
6
7 public staticAndroidTimeReadgetInstance(){
8 returnInstaceHolder.instance;
9}
10
11 privateAndroidTimeRead(){}
12
13 publicTimeviewmodelshowTime(){
14Timeviewmodelmodel= newTimeviewmodel();
15model.setTime(String.valueOf(System.currentTimeMillis()));
16 returnmodel;
17}
18
19}
1Timeviewmodelviewmodel=AndroidTimeRead.getInstance().showTime();调用修改
这里去掉了静态的方式,可是却没有解除直接依赖实现的问题。
关注行为
3}
1privateITimeServicetimeService;
3 public voidsetTimeService(ITimeServicetimeService){
4 this.timeService=timeService;
5}
6
7@Override
8 protected voidonCreate(BundlesavedInstanceState){
9 super.onCreate(savedInstanceState);
10setContentView(R.layout.activity_main);
11
12txtShowTime=(TextView)findViewById(R.id.txtShowTime);
13btnShow=(Button)findViewById(R.id.btnShow);
14btnShow.setOnClickListener( newView.OnClickListener(){
15
16@Override
17 public voidonClick(Viewv){
18Timeviewmodelviewmodel=timeService.showTime();
19txtShowTime.setText(viewmodel.getTime());
20}
21});
22
23}
遗憾的是上面的程序不能正常运行,ITimeService 没有实例化。我们虽然提供了注入点,但是Activity 的生命周期由系统接管,我们无法直接使用。
事实上当你使用Roboguice 时也是需要继承自其提供的RoboActivity。
完成业务代码
在引入Roboguice 前先完成Demo的结构。添加ITimeRepository 和对应的实现,并让AndroidTimeRead 依赖 ITimeRepository。
1 public classTimeModel{
2 public longCurrentTime;
3}
4 public interfaceITimeRepository{
5TimeModelquery();
6}
@Override
publicTimeModelquery(){
TimeModelmodel= newTimeModel();
model.CurrentTime=System.currentTimeMillis();
returnmodel;
}
}
引入Roboguice 应该放在哪里?
命名一个Infrastructure包,将需要的基础设施放置在此。
引入RoboActivity
2
3@InjectView(R.id.txtShowTime)
4 privateTextViewtxtShowTime;
5@InjectView(R.id.btnShow)
6 privateButtonbtnShow;
7
8@Inject
9 privateITimeServicetimeService;
10 // 提供注入点
11 public voidsetTimeService(ITimeServicetimeService){
12 this.timeService=timeService;
13}
14
15@Override
16 protected voidonCreate(BundlesavedInstanceState){
17 super.onCreate(savedInstanceState);
18setContentView(R.layout.activity_main);
19
20btnShow.setOnClickListener( newView.OnClickListener(){
21
22@Override
23 public voidonClick(Viewv){
24Timeviewmodelviewmodel=timeService.showTime();
25txtShowTime.setText(viewmodel.getTime());
26}
27});
28
29}
2
3@Override
4 public voidonCreate(){
5 super.onCreate();
6RoboGuice.setBaseApplicationInjector( this,RoboGuice.DEFAULT_STAGE,
7RoboGuice.newDefaultRoboModule( this),newTimeModule());
8}
9}
2
3@Override
4 public voidconfigure(Binderbinder){
5 // 顺序无关,在具体的Activity中被创建
6 binder
7.bind(ITimeService. class)
8.to(AndroidTimeRead. class);
9 // .in(Singleton.class); // 单件
10
11binder.bind(ITimeRepository. class)
12.to(TimeRepository. class);
13
14}
15
16}
3 return newAndroidTimeRead(rep);
4}
2
3@Inject
4ITimeRepositoryrep;
5
6@Override
7 publicAndroidTimeReadget(){
8
9 return newAndroidTimeRead(rep);
10}
11
12}
3 // 顺序无关,在具体的Activity中被创建
4 binder
5.bind(ITimeService. class)
6.to(AndroidTimeRead. class);
7 // .in(Singleton.class); // 单件
8
9binder.bind(ITimeRepository. class)
10.to(TimeRepository. class);
11
12binder.bind(AndroidTimeRead. class)
13.toProvider(AndroidTimeReadProvider. class);
14
15}
引入注入框架需要的思考:
3、其他可选择的框架如 dagger