前言
好久沒寫博客了,罪過啊~記事本里累積了不少東西,整理整理放上來。
關於依賴注入
通常博主開發項目時喜歡以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 服務層。
項目包結構

使用靜態類的實現方式
1 public class AndroidTimeRead {
3 public static TimeViewModel showTime() {
4 TimeViewModel model = new TimeViewModel();
5 model.setTime(String. valueOf(System.currentTimeMillis ()));
6 return model;
7 }
8
9 }
10
11 public class MainActivity extends Activity {
12
13 private TextView txtShowTime ;
14 private Button btnShow ;
15
16 @Override
17 protected void onCreate(Bundle savedInstanceState) {
18 super.onCreate(savedInstanceState);
19 setContentView(R.layout. activity_main);
20
21 txtShowTime = (TextView) findViewById(R.id.txtShowTime);
22 btnShow = (Button) findViewById(R.id. btnShow);
23 btnShow.setOnClickListener( new View.OnClickListener() {
24
25 @Override
26 public void onClick(View v) {
27 TimeViewModel viewModel = AndroidTimeRead. showTime();
28 txtShowTime.setText(viewModel.getTime());
29 }
30 });
31
32 }
33
34 }
另一個問題是:當你想對MainActivity 進行單元測試,你會發現非常困難,AndroidTimeRead 必須被包含進來,如果它還引用了其他的組件(如Db 或 net),那么這些組件也必須包含入內。 靜態類型因為一直在內存中,如果它引用了其他類型,則被引用的對象CG無法回收。
改進
2
3 private static class InstaceHolder{
4 public static AndroidTimeRead instance= new AndroidTimeRead();
5 }
6
7 public static AndroidTimeRead getInstance(){
8 return InstaceHolder.instance;
9 }
10
11 private AndroidTimeRead(){}
12
13 public TimeViewModel showTime() {
14 TimeViewModel model = new TimeViewModel();
15 model.setTime(String. valueOf(System.currentTimeMillis ()));
16 return model;
17 }
18
19 }
1 TimeViewModel viewModel = AndroidTimeRead. getInstance().showTime();調用修改
這里去掉了靜態的方式,可是卻沒有解除直接依賴實現的問題。
關注行為
2 TimeViewModel showTime();
3 }
1 private ITimeService timeService ;
3 public void setTimeService(ITimeService timeService) {
4 this.timeService = timeService;
5 }
6
7 @Override
8 protected void onCreate(Bundle savedInstanceState) {
9 super.onCreate(savedInstanceState);
10 setContentView(R.layout. activity_main);
11
12 txtShowTime = (TextView) findViewById(R.id.txtShowTime);
13 btnShow = (Button) findViewById(R.id. btnShow);
14 btnShow.setOnClickListener( new View.OnClickListener() {
15
16 @Override
17 public void onClick(View v) {
18 TimeViewModel viewModel = timeService.showTime();
19 txtShowTime.setText(viewModel.getTime());
20 }
21 });
22
23 }
遺憾的是上面的程序不能正常運行,ITimeService 沒有實例化。我們雖然提供了注入點,但是Activity 的生命周期由系統接管,我們無法直接使用。
事實上當你使用Roboguice 時也是需要繼承自其提供的RoboActivity。
完成業務代碼
在引入Roboguice 前先完成Demo的結構。添加ITimeRepository 和對應的實現,並讓AndroidTimeRead 依賴 ITimeRepository。
1 public class TimeModel {
2 public long CurrentTime ;
3 }
4 public interface ITimeRepository {
5 TimeModel query();
6 }
@Override
public TimeModel query() {
TimeModel model= new TimeModel();
model.CurrentTime=System. currentTimeMillis();
return model;
}
}
private ITimeRepository rep ;
public AndroidTimeRead(ITimeRepository rep) {
this.rep = rep;
}
public TimeViewModel showTime() {
TimeViewModel model = new TimeViewModel();
model.setTime( "現在的時間是" + String.valueOf( rep.query()));
return model;
}
}
引入Roboguice 應該放在哪里?
命名一個Infrastructure包,將需要的基礎設施放置在此。
引入RoboActivity
2
3 @InjectView(R.id.txtShowTime )
4 private TextView txtShowTime ;
5 @InjectView(R.id.btnShow )
6 private Button btnShow ;
7
8 @Inject
9 private ITimeService timeService ;
10 // 提供注入點
11 public void setTimeService(ITimeService timeService) {
12 this.timeService = timeService;
13 }
14
15 @Override
16 protected void onCreate(Bundle savedInstanceState) {
17 super.onCreate(savedInstanceState);
18 setContentView(R.layout. activity_main);
19
20 btnShow.setOnClickListener( new View.OnClickListener() {
21
22 @Override
23 public void onClick(View v) {
24 TimeViewModel viewModel = timeService.showTime();
25 txtShowTime.setText(viewModel.getTime());
26 }
27 });
28
29 }
2
3 @Override
4 public void onCreate() {
5 super.onCreate();
6 RoboGuice. setBaseApplicationInjector( this, RoboGuice. DEFAULT_STAGE,
7 RoboGuice. newDefaultRoboModule( this), new TimeModule());
8 }
9 }
2
3 @Override
4 public void configure(Binder binder) {
5 // 順序無關,在具體的Activity中 被創建
6 binder
7 .bind(ITimeService. class)
8 .to(AndroidTimeRead. class);
9 // .in(Singleton.class); // 單件
10
11 binder.bind(ITimeRepository. class)
12 .to(TimeRepository. class);
13
14 }
15
16 }
3 return new AndroidTimeRead(rep);
4 }
2
3 @Inject
4 ITimeRepository rep;
5
6 @Override
7 public AndroidTimeRead get() {
8
9 return new AndroidTimeRead( rep );
10 }
11
12 }
3 // 順序無關,在具體的Activity中 被創建
4 binder
5 .bind(ITimeService. class )
6 .to(AndroidTimeRead. class );
7 // .in(Singleton.class); // 單件
8
9 binder.bind(ITimeRepository. class )
10 .to(TimeRepository. class );
11
12 binder.bind(AndroidTimeRead. class )
13 .toProvider(AndroidTimeReadProvider. class );
14
15 }

引入注入框架需要的思考:
3、其他可選擇的框架如 dagger