Dagger2总结

简单总结一下  方便日后查询



     Dagger2是为了解决对象依赖关系而生的依赖注入框架 目的是为了降低代码耦合   它会在编译后自动为被inject的类添加所需要new出对应对象的代码
    

    用大白话说 
    就比如 

@Inject  
User user;  
@Override  
protected void onCreate(Bundle savedInstanceState) {  
    super.onCreate(savedInstanceState);  
    setContentView(R.layout.activity_c);  
    DaggerCActivityComponent.builder().cUserModule(new CUserModule()).build().inject(this);  
    TextView tv = (TextView) findViewById(R.id.tv);  
    tv.setText(user.toString());  
}  


    这里先@inject User user 看到这个 意味着我们下面的代码 等会如果哪里要用到这个user 实例了 就不需要重新new了  Dagger2会在编译的时候自动帮我们new出来


1引用


    
     在项目中引入Dagger2需要修改两个地方的gradle文件,首先是project的gradle文件,修改成如下样子:

dependencies {  
        classpath 'com.android.tools.build:gradle:2.1.0'  
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'  
  
        // NOTE: Do not place your application dependencies here; they belong  
        // in the individual module build.gradle files  
    }  





然后修改module的gradle文件:

apply plugin: 'com.neenbedankt.android-apt'  
dependencies {  
    compile fileTree(include: ['*.jar'], dir: 'libs')  
    testCompile 'junit:junit:4.12'  
    compile 'com.android.support:appcompat-v7:24.1.1'  
    compile 'com.google.dagger:dagger:2.6'  
    apt 'com.google.dagger:dagger-compiler:2.6'  
    compile 'com.squareup.picasso:picasso:2.5.2'  
}  






      这里有几个地方需要说一下,首先Dagger2我们可以直接在jCenter中搜索到的,可以搜到之后直接添加,那么和Dagger2有关的是两个文件:

compile 'com.google.dagger:dagger:2.6'  
apt 'com.google.dagger:dagger-compiler:2.6'  


    但是这两个一个用了compile一个用了apt,使用apt表示该引用类库只在编译的时候起作用,在打包的时候并不会打包到apk中去。


2 @Module

    前面说了 只要用了@inject 标注一下依赖到的类 User 那么Dagger2会在编译后自动帮我们生成这个类的实例user,但Dagger2怎么知道如何new 出一个User的实例呢? 需要我们自己定义一个类使用@Module标注  然后在这个Module类里面 我们通过一个方法 
@Module  
public class UserModule {  
    @Provides  
    @Singleton  
    User providesUser() {  
        return new User();  
    }  
}  


 povidesUser() 方法返回了一个User对象


3 @Provides

     那么当我为这个Activity注入了user的依赖之后,Dagger会在被@Module注解的代码里寻找对应的返回值一致的方法,什么代码负责告诉Dagger2对应的类的生成方法呢?

     也就是说Dagger2自动生成的new出User类的那些代码 在哪里定义呢?
     就在Module里被@Provides修饰的方法里定义  


     这里providersUser()方法刚好返回的是User对象  方法体很简单就是new User();


   所以当Activity在用到User对象的时候,它就知道,我需要去Module里找对应的生成方法了,找到对应的Module     后,再在Module里找被@Provides修饰的方法,这个方法就为Dragger2提供了构建新对象的具体方法



4@Component 


     看到了@Module和@provides之后 还有一个疑问 就是   我知道被inject之后 一旦需要用到它的实体  我会到modules里面找  但Dagger2里 modules并不止一个  

     事实上 Dagger2允许你自定义无穷多的Modules   只要一个类里 有provides方法  然后被@Modules修饰 它就算是一个Module  。

     那么多的Modules 如何告诉Dagger去那个里面找 这就需要用到一个新的注解 叫做@Component  

 

     一个Component 就类似一个注射器   他把药物 Modules 和 病人 (使用了依赖对象的类 比如这里片头的Activity )联系在了一起

     他的定义方式很简单
@Singleton  
@Component(modules = UserModule.class)  
public interface ActivityComponent {  
    void inject(MainActivity activity);  
}  



   

  先用@Component注解修饰 告诉Dragger2这是一个组件(注射器),后面(modules=xxxModule.class , yyyModule.class...)告诉这个注射器可以打哪几种药物,组件都是接口,接口中定义了inject方法,这里的inject方法中需要传入一个病人对象,比如这里传入的是MainActivity ,这样一来,一个注射器就定义好了,他把Modules和注入的对象联系在一起了,这里可以定义多个带有不同参数的jnject方法 比如

@UserScope  
@Component(modules = UserModule.class)  
public interface ActivityComponent {  
    void inject(MainActivity activity);  
  
    void inject(BActivity activity);  
}  




 这涉及到下面要说的 @scope注解了


5@scope

   顾名思义  他是用来定义作用域的


     前面用的@singleton 是系统自带的一个scope 被它修饰的类它意味着在整个项目中只有一个实体 ,也就是全局单利  模式,在实际开发过程中,除了全局单例,更常见的是局部单例,比如

以下参考博主

http://blog.csdn.net/u012702547/article/details/52213706


    我们有三个Activity,MainActivity,BActivity和CActivity,我们想让MainActivity和BActivity共享同一个实例,而让CActivity获取另外一个实例,这又该怎么实现呢?在Dagger2中,我们可以通过自定义Scope来实现局部单例。

首先让我们先来定义一个局部作用域:
 
@Scope  
@Retention(RetentionPolicy.RUNTIME)  
public @interface UserScope {  
}  



然后在我们的UserModule和ActivityComponent中应用该局部作用域:

@Module  
public class UserModule {  
    @Provides  
    @UserScope  
    User providesUser() {  
        return new User();  
    }  
}  





@UserScope  
@Component(modules = UserModule.class)  
public interface ActivityComponent {  
    void inject(MainActivity activity);  
  
    void inject(BActivity activity);  
}  




   请大家注意,我的ActivityComponent作为一个注入器只可以向MainActivity和BActivity两个Activity中注入依赖,不可以向CActivity中注入依赖。最后,要让该局部作用域产生单例效果,需要我们在自定义的Appliation类中来初始化这个Component,如下:

public class MyApp extends Application {  
    ActivityComponent activityComponent;  
    @Override  
    public void onCreate() {  
        super.onCreate();  
        activityComponent = DaggerActivityComponent.builder().userModule(new UserModule()).build();  
    }  
  
    ActivityComponent getActivityComponent(){  
        return activityComponent;  
    }  
}  


接下来我们在MainActivity和BActivity中注入依赖,MainActivity如下:

    
@Inject  
    User user;  
    @Inject  
    User user2;  
    private TextView tv;  
    private TextView tv2;  
  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
//        DaggerActivityComponent.builder().userModule(new UserModule()).build().inject(this);  
        ((MyApp) getApplication()).getActivityComponent().inject(this);  
        tv = ((TextView) findViewById(R.id.tv));  
        tv2 = ((TextView) findViewById(R.id.tv2));  
        tv.setText(user.toString());  
        tv2.setText(user2.toString());  
    }  



BActivity如下:
  
@Inject  
User user;  
  
@Override  
protected void onCreate(Bundle savedInstanceState) {  
    super.onCreate(savedInstanceState);  
    setContentView(R.layout.activity_b);  
    ((MyApp) getApplication()).getActivityComponent().inject(this);  
    TextView tv = (TextView) findViewById(R.id.tv);  
    tv.setText(user.toString());  
}  



那么如果我还想在CActivity中使用User对象该怎么办呢?再来一个CUserModule和CActivityComponent
CUserModule如下:

@Module  
public class CUserModule {  
    @Provides  
    User providesUser() {  
        return new User();  
    }  
}  


这里没有再著名单例

CActivityComponent如下:

@Component(modules = CUserModule.class)  
public interface CActivityComponent {  
    void inject(CActivity activity);  
}  



在CActivity中注入依赖:

@Inject  
User user;  
@Override  
protected void onCreate(Bundle savedInstanceState) {  
    super.onCreate(savedInstanceState);  
    setContentView(R.layout.activity_c);  
    DaggerCActivityComponent.builder().cUserModule(new CUserModule()).build().inject(this);  
    TextView tv = (TextView) findViewById(R.id.tv);  
    tv.setText(user.toString());  
}  



运行结果如下:


    可以看到,MainActivity和BActivity是同一个实例,而CActivity则是另外一个实例。
@UserScope在这里到底起了什么作用?我引用网上一段话:
以下文字来源:http://blog.csdn.net/u012943767/article/details/51941872


    Scope的使用,如何实现单例?  
  
这个迷之Scope也是有点难以理解,我们在哪里使用到了Scope呢。在我们的AppComponent中添加了一个注解为@Singleton,@Singleton就是一个Scope,据说可以实现单例哟。。。难道这样就实现了单例模式?我刚刚开始是这样理解的。直到仔细的看了几遍这篇文章我才知道并不是这样的。  
  
事实上@Sinleton中并没有创建单例的能力,那么AppComponent中提供的依赖注入是如何实现单例的呢。其实这个原理很贱单。  
  
首先Module提供了创建实例的方法,接着AppComponent中对Module进行管理,最后AppComponent在自定义Applicaiton中被实例化了一次。  
  
这个实例化了一次是最重要的呀。仅仅被实例化了一次,那不就是单例么。就是这么简单呀。  
  
可能有些童靴当时就不乐意了,那既然这样都已经实现了单例,那么这个@Singltop还要来何用?不是多此一举吗。  
  
其实@Singletop还有有一些作用的,首先一方面能让你直面的了解到这是一个单例,其次这个@Singletop能够更好的管理Modlue和Component之间的关系。  
  
Dagger2需要保证Component和Module是匹配的,就需要用到这个注解。  




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章