- 1.含义
- 1)依赖是指一个对象持有其他对象的引用。依赖注入则是将这些依赖对象传递给被依赖对象,而不是被依赖对象自己创建这些对象,说白了注入就是对象作为参数传递。
public class MyClass{
private AnotherClass mAnotherObject;
public MyClass(){
mAnotherObject = new AnotherClass();
}
}
2)通过传递对象的方式,所传递对象的更改不会影响代码。
public class MyClass{
private MyInterface mAnotherObject;
public MyClass(MyInterface anotherObject){
mAnotherObject = anotherObject;
}
}
3)依赖注入可以简化代码编写,并提供一个可适配的环境,方便进行单元测试以及功能模块的配置。
- 2.例子以及应用场景
- 1)问题:某Android应用需要一个列表来显示用户的好友。
• “`java
public class FriendListFragment{
private FriendListAPI mFriendListAPI;
……
public FriendListFragment(){
mFriendListAPI = new FriendListAPI();
}
private void getFriendList(){
mFriendListAPI.getFriendList(new Callback(){
public void onSuccess(List list){
……
}
……
});
}
}
public class FriendListAPI{
private OkHttpClient mHttpClient;
public FriendListAPI(){
mHttpClient= new OkHttpClient();
//接下来各种Http配置 ……
}
}
- 2)技巧一:后台API没有准备好或者没有数据怎么办?自己添点测试数据试试吧。在FriendListFragment里面添加一个生成测试数据的方法buildTestData(),并替换getFriendList()方法。等后台API准备好后再改回来。
- 3)技巧二:测试网络有延迟或错误的时候,程序是否会出现异常。这需要通过配置OkHttpClient参数来实现测试场景,于是又要更改FriendListAPI中相关HttpClient配置代码,测试完后再修改回来。
- 4)以上两点虽然是技巧,其实也是问题,那么问题来了:这样对代码进行多次修改,很容易出错。因此,对于多次使用的模块,我们可以通过注入的方式,将引用传入需要使用的类中,而不是自己创建。通过编写两个API,一个是直接请求后台数据,另一个则只是一些静态测试数据。需要测试的时候注入可生成测试数据的API,测试完后则切换为正式API。
```java
public class FriendListFragment{
private FriendListAPI mFriendListAPI;
public FriendListFragment(FriendListAPI friendListAPI){
mFriendListAPI = friendListAPI;
}
}
public class FriendListAPI{
private OkHttpClient mHttpClient;
public FriendListAPI(HttpClient okHttpClient){
mHttpClient= okHttpClient;
......
}
}
```
- 5)继续引入问题:引入一个稍微复杂的场景,更多的Fragment需要使用FriendListAPI,我们需要在两个不同的地方进行注入,因此产生了许多重复代码。
- 6)解决方案:因此,我们需要一个容器,它知道什么地方需要注入,注入什么样的对象。
- 7)Dagger:展示轻量级依赖注入库Dagger实现的注入
首先定义模块:
public class MyModule{
@Provides @Singleton OkHttpClient provideOkHttpClient(){
//这里可进行各种Http配置
return new OkHttpClient();
}
@Provides @Singleton FriendListAPI provideFriendListAPI(){
return newFriendListAPI();
}
}
初始化模块以及依赖对象图:
public class MyApplication extends Application{
private ObjectGraph graph;
@Override public void onCreate() {
super.onCreate();
graph = ObjectGraph.create(getModules().toArray());
}
protected List<Object> getModules() {
return Arrays.asList(
new MyModule(this));
}
public void inject(Object object) {
graph.inject(object);
}
}
最后添加注入点并进行注入
public abstract class BaseActivity extends FragmentActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
((MyApplication) getApplication()).inject(this);
}
}
public class FriendListFragment{
@Inject FriendListAPI mFriendListAPI;
……
}
public class FriendListAPI{
@Inject OkHttpClient mHttpClient;
……
}
“`
3.应用场景
1)当你需要将配置数据注入到一个或多个模块时。在开发过程中前端访问后台服务器地址会分为测试服务器和正式服务器,以及各种第三方分享key和ID,依赖注入都是非常好的选择。
2)当需要将同一依赖注入到多个模块时。如加载图片以及图片存储管理组件(Picasso, Android-Universal-Image-Loader)
3)当需要对同一依赖注入不同的实现时。为方便开发和单元测试,后台API可有正式API和模拟API,通过依赖注入方便切换环境。
4)当同一模块需要注入不同的配置时。
4.原理
1)基于反射的依赖注入框架(Guice、RoboGuice):性能差。已经废弃,原因是他们会在程序运行的时候需要扫描代码中的注解,并映射到内存中,耗时。
2)Dagger:因为它使用了编译时注解,也就是说在编译代码的时候,Dagger就已经完成传统依赖注入框架在运行时所执行的任务,把它当做应用中的一个模块, 负责为其它模块提供实例并且注入依赖关系。那是它的基本职责。模块的创建位于我们应用中的一个点上,这样我们可以拥有完全的控制权。
http://www.mamicode.com/info-detail-599464.html
http://square.github.io/dagger/
https://github.com/JakeWharton/butterknife
http://objccn.io/issue-11-6/
推荐butterknief和androidstudio上面的一个插件配合使用,叫ButterKnief Zelezny。