Android开发中依赖注入的应用

什么是依赖注入?

  依赖是指一个对象持有其余对象的引用。依赖注入则是将这些依赖对象传递给被依赖对象,而不是被依赖对象本身建立这些对象。 
public class MyClass{
     private AnotherClass mAnotherObject;
 
     public MyClass(){
          mAnotherObject = new AnotherClass();
     }
}
 
  经过传递对象的方式,所传递对象的更改不会影响代码。 
public class MyClass{
     private MyInterface mAnotherObject;
 
     public MyClass(MyInterface anotherObject){
          mAnotherObject = anotherObject;
     }
}

  依赖注入能够简化代码编写,并提供一个可适配的环境,方便进行单元测试以及功能模块的配置。 前端

开发中可能会遇到这样的麻烦。

  咱们将经过一个例子来理解依赖注入的应用场景:某Android应用须要一个列表来显示用户的好友。 
public class FriendListFragment{
     private FriendListAPI mFriendListAPI;
     ......
 
     public FriendListFragment(){
          mFriendListAPI = new FriendListAPI();
     }
 
     private void getFriendList(){
          mFriendListAPI.getFriendList(new Callback(){
               public void onSuccess(List<User> list){
                    ......
               }
               ......
          });
     }
}
 
public class FriendListAPI{
     private OkHttpClient mHttpClient;
 
     public FriendListAPI(){
          mHttpClient= new OkHttpClient();
          //接下来各类Http配置
          ......
     }
}

  代码写好了,运行程序试试。但是,后台API没有准备好或者没有数据怎么办?本身添点测试数据试试吧。在FriendListFragment里面添加一个生成测试数据的方方法buildTestData(),并替换getFriendList()方法。等后台API准备好后再改回来。git

  咱们想测试网络有延迟或错误的时候,程序是否会出现异常。这须要经过配置OkHttpClient参数来实现测试场景,因而又要更改FriendListAPI中相关HttpClient配置代码,测试完后再修改回来。
  这样对代码进行屡次修改,很容易出错。所以,对于屡次使用的模块,咱们能够经过注入的方式,将引用传入须要使用的类中,而不是本身建立。经过编写两个API,一个是直接请求后台数据,另外一个则只是一些静态测试数据。须要测试的时候注入可生成测试数据的API,测试完后则切换为正式API。 
public class FriendListFragment{
     private FriendListAPI mFriendListAPI;
     ......
 
     public FriendListFragment(FriendListAPI friendListAPI){
          mFriendListAPI = friendListAPI;
     }
}
 
public class FriendListAPI{
     private OkHttpClient mHttpClient;
 
     public FriendListAPI(HttpClient okHttpClient){
          mHttpClient= okHttpClient;
          ......
     }
}

  如今引入一个稍微复杂的场景,更多的Fragment须要使用FriendListAPI,咱们须要在两个不一样的地方进行注入,所以产生了许多重复代码。github

  所以,咱们须要一个容器,它知道什么地方须要注入,注入什么样的对象。 

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;
     ......
}

  如需进行单元测试,或使用可生成测试数据的模拟API,则再编写一个模块,在初始模块和依赖对象图时替换便可。框架

现有的依赖注入性能?

  依赖注入虽能简化代码编写,方便单元测试,但是因为当前基于反射的依赖注入框架( GuiceRoboGuice)性能并很差。缘由是他们会在程序运行的时候须要扫描代码中的注解,并须要花费内存映射到内存中。
  这里推荐使用Dagger是由于它使用了编译时注解,也就是说在编译代码的时候,Dagger就已经完成传统依赖注入框架在运行时所执行的任务。

何时须要依赖注入?

  当你须要将配置数据注入到一个或多个模块时。在开发过程当中前端访问后台服务器地址会分为测试服务器和正式服务器,以及各类第三方分享key和ID,依赖注入都是很是好的选择。
  当须要将同一依赖注入到多个模块时。如加载图片以及图片存储管理组件(Picasso, Android-Universal-Image-Loader)。
  当须要对同一依赖注入不一样的实现时。为方便开发和单元测试,后台API可有正式API和模拟API,经过依赖注入方便切换环境。
  当同一模块须要注入不一样的配置时。

参考资料:

http://square.github.io/dagger/
相关文章
相关标签/搜索