关于Dagger2的一些个人理解

写作目的

现在基本上有一些规模的项目,都使用了Dagger2,也不是装13,个人感觉也的确是大势所趋,Dagger2的确有它的优势。借着手上的项目,学习了一下Dagger2,打算用在公司的项目中。今天就来以自己初学者的角度来谈谈dagger2的认识。

问题由来

我是目前是移动端开发者,主要从事的是Android端开发。在andorid开发过程中,按照套路我们会有SharePreferenceManager、DatabaseManager、NetWorkManager、CacheManager等各种Manager,当然你的叫法也可以不同,他们都会存在初始化,考虑到有种可能的初始化顺序,如下图:
关于Dagger2的一些个人理解_第1张图片

我们可能需要先使用Application初始化SpManager(SharePreferenceManager)拿到一些关键数据,从而通过这些数据来初始化DbManager,NWManager或者CacheManager。可以看到我们的各个对象就存在初始化先后的问题,试想如果系统过于复杂,像这种对象初始化有相互依赖的各种关系,想必是非常复杂的;如果是我们用代码去写,也是很繁杂的而且没多大效率的;还有一个问题,看下图:
关于Dagger2的一些个人理解_第2张图片
如果有一天,我们的E对象突然改变了初始化方法,而且很多地方都需要E对象的初始化,那我们是不是很懵,因为有很多地方需要修改,那苦逼的程序员是不是很难受,这也就是我们常说的程序的耦合性,改一处,就要变100处地方。很显然dagger的出现就是为了解决这个问题的。具体怎么解决,我还有想用一张图来说明我的想法:
关于Dagger2的一些个人理解_第3张图片

假设dagger在初始化某对象时,同时需要a b c g四个对象,它就会在容器中寻找(这里的寻找有可能是上一次创建的),找到了就拿来使用,没有找到就需要靠自身去创建了。你可以看到a d g对象都会存在,此时c对象不存在,那么此时的c对象的创建又变成了XObject对象的创建,此时需要找到c对象创建时,需要m对象和p对象,一环一环套下去,然后直到所有的需要的对象都创建完成,然后再递归到需要它需要创建的对象,直到所有的对象初始化完成。明白了这个道理,感觉学习dagger2就不难了。

开始Dagger2

配置

AS , gradle配置:

    //dagger2
    compile 'com.google.dagger:dagger:2.14.1'
    annotationProcessor 'com.google.dagger:dagger-compiler:2.14.1'

新建Student类:

public class Student {
    private String name ;
    private int score ;

    @Inject
    public Student(){
        this.name = "zhangsan" ;
        this.score = 30 ;
    }

    public Student(String name, int score) {
        this.name = name;
        this.score = score;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", score=" + score +
                '}';
    }
}

和普通java类一致,只是在构造方法上使用了注解@javax.inject.Inject注解,第一步完成;

创建接口StudentComponent,当然这个接口名字你可以乱写,但是为了规范我还是建议你初始化啥对象,就写这个名字,接口很简单:

@Component
public interface StudentComponent {
    void inject(SecondActivity activity);
}

我们需要一个@dagger.Component的注解,和一个SecondActivity,这个SecondActivity是我们需要用到的Activity,在这个Activity中我们需要对Student对象进行初始化:
SecondActivity源码:

public class SecondActivity extends AppCompatActivity {

    @Inject
    Student su;

    TextView tv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        tv = findViewById(R.id.id_tv_content);
    }

    public void getStudentInfo(View view) {
        tv.setText(su.toString());
    }
}

在我们需要的初始化的对象上Student也加上@Inject注解,其他的好像真的完事了,就这么简单?当然,你需要将make一下你的project(这里吐槽一下当年使用window系统最终放弃了dagger2无数次,make项目绝对是我不想坚持下去的最大原因,太尼玛花时间了),然后加上一句话:
关于Dagger2的一些个人理解_第4张图片
编译运行,我们可以看到:
关于Dagger2的一些个人理解_第5张图片
的确,程序没有我们想象中报了异常,而是真的被初始化,而且被赋值了。第一次用Dagger2的感觉就是这么神奇。当然这算得上Dagger2最简单的应用场景吧。

不过,距离真正去使用Dagger2还有有一定的差距,因为我们还缺少一样叫module的类。真正的Dagger2是存在三部分的。
1. 对象的实例化部分,相当于我们的new Object(); Dagger提供类似容器功能,提供实例化的功能;这一个叫module
2. 需要实例化的部分,你实例化的对象需要被用得到,这是个非常抽象的部分,可以使是Activity,也可以是Fragment,或者是任意的Java对象
3. 连接部分,将实例化的对象和需要用到这些对象的部分连接起来。这一个在dagger中叫Component

好了,有了上面的简单说明,我们来个真正的dagger用法。来个Student2对象,相当于我们的数据:


public class Student2 {
    private String name ;
    private int score ;

    public Student2(String name, int score) {
        this.name = name;
        this.score = score;
    }

    @Override
    public String toString() {
        return "Student2{" +
                "name='" + name + '\'' +
                ", score=" + score +
                '}';
    }
}

现在我们需要module组件,给我们提供对象实例化的,这个可能稍微有点拐弯:

@Module
public class Student2Module {

    @Provides
    public String provideName() {
        return "lisi" ;
    }

    @Provides
    public int provideScore(){
        return 98 ;
    }

    @Provides
    public Student2 provideStudent2(String name , int score){
        return new Student2(name,score);
    }
}

我们看到了@provides,这是来自Dagger的注解,正如翻译过来,就是给你提供数据量,它提供了一个Student2对象,那么问题来了,那namescore是哪里来的呢?同样我们看到了它提供另外两个方法provideScore()provideName(),同样也被@Provides注解修饰,意思就是我给你提供数据量。

已经有数据可以提供了,那哪里需要这个数据呢?来,看一下我们的Activity,在Activity中有地方需要它:

public class ThirdActivity extends AppCompatActivity {

    @Inject     //这里使用@Inject 说明我需要被初始化
    Student2 stu ;

    TextView tv ;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
       tv = findViewById(R.id.id_tv_content);
    }

    //这里是按钮的点击作用,我们需要看一下这个Student2对象是否被初始化  
    public void getStudentInfo(View v) {
        tv.setText(stu.toString());
    }

}

数据源和数据去向都有了,那我们就需要一个中间的连接着Component了,好了,我们来造一个Component,如下:

@Component(modules = Student2Module.class)  //这就是中间的链接部分,数据源就是这个modules所对应的数据类
public interface Student2Component {    //Component是接口,相当于中间件

    void inject(ThirdActivity activity);  //这个是数据去向,注意不要使用什么BaseActivity,一定要写具体的activity
}

好了,然后我们make(build,reBuild)一下我们的项目,然后在ThirdActivity中添加一句代码:
关于Dagger2的一些个人理解_第6张图片
这个DaggerStudentComponent是Dagger框架自动生成的,它是由你的Component接口然后加上Dagger前缀生成的,作用是连接我们的数据源和数据接收者。点击按钮,可以看到结果:
关于Dagger2的一些个人理解_第7张图片
结果就是我们想要的,也可以看到Student2Module中提供的name和score的确在ActivityStudent2对象中了。是不是很简单呢?是啊,我们的dagger注入框架就好了,这就是注入的效果。

但是你有没有一种感觉,为啥Student类和Student2对象中,Student构造器中使用了@Inject注解,但是Student2构造器中没有使用@Inject呢;为啥Student对应的StudentComponent没有提供获取Student方法,而Student2Component中提供了获取Student2的方法呢?

这就需要我们理解Module作为数据提供者,提供数据也是有先后顺序的,一般顺序如下:
1. 我现在module数据提供者中找有没有提供初始化对象的方法;
2. 我找到了,我就返回该对象;
3. 我没有找到,我就去查看这个对象的构造器是否被@Inject找到
4. 找到了,那么自己执行new Object过程;没有找到,对不起,编译出错,说明你dagger方法使用错误。

所以,综上所述,一个对象的构造器Constructor没有被@Inject修饰,那么在Module中必须有方法提供初始化对象。

好了,我们接下来就说一说工作和生活中用得比较多的对象,也就是关于dagger的标识符问题了。

@Singleton

和Java思想中一致,就是单例的意思。这里的单例依据个人的理解,一个数据接收容器中存在多个数据接收者,那么多个数据接收者指向的对象是同一个。说的自己都有点不信了,举个例子:
定义StudentSingleton数据结构:

@Singleton
public class StudentSingleton {

    private String name ;
    private int score ;

    @Inject //看这里被@Inject修饰了
    public StudentSingleton(String name, int score) {
        this.name = name;
        this.score = score;
    }

}

数据提供者StudentSingletonModule

@Module
public class StudentSingletonModule {

    @Provides
    public String getName(){
        return "tom";
    }

    @Provides
    public int score() {
        return 20;
    }

}

数据需求者SingletonActivity,可以看得到里面有两个StudentSingleton对象等待被初始化:

public class SingletonActivity extends AppCompatActivity {

    @Inject
    StudentSingleton singleton1 ;

    @Inject
    StudentSingleton singleton2 ;

    TextView tv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);

        tv = findViewById(R.id.id_tv_content);

        //build之后 进行对象注入
        DaggerStudentSingleComponent.builder().build().inject(this);
    }

    public void getStudentInfo(View v) {
        tv.setText(singleton1 + "\n" + singleton2);
    }
}

我们看一下结果:
关于Dagger2的一些个人理解_第8张图片
我们可以看到两个StudentSingleton对象指向的相同的地址,那么说明它们是同一个对象。
同样,我们在另外一个Activity中也需要一个StudentSingleton,如下代码:

public class AnotherStudentSingletonActivity extends AppCompatActivity {

    @Inject
    StudentSingleton stu ;

    TextView tv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_another_student_singleton);

        tv = findViewById(R.id.id_tv_content);

        DaggerStudentSingleComponent.builder().build().inject(this);
    tv.setText(stu.toString());
    }
}

获取的结果为:
关于Dagger2的一些个人理解_第9张图片
由此可见,@Singleton注解并不是我们平常意义上的单例,只是在同一个容器的中,指向同一个对象才可能被称为单例。

当然了,你去掉@Singleton注解,去看看在一个Activity同时获取两个StudentSingleton对象,地址是不是一样呢?答案肯定是不一样的。

初始化对象时,需要获取外部参数

这个在Andorid中需求的比较多,很多时候我们需要一个Context对象,到处都是Context对象,举个例子:
先来个StudentContext对象:

public class StudentContext {
    private String name ;
    private int score ;
    private Context context;

    public StudentContext(){}

    @Inject  //注意@Inject注解修饰的这个构造器
    public StudentContext(String name, int score, Context context) {
        this.name = name;
        this.score = score;
        this.context = context;
    }

    @Override
    public String toString() {
        return "StudentContext{" +
                "name='" + name + '\'' +
                ", score=" + score +
                ", context=" + context +
                '}';
    }
}

在我们的Module中,我们这时需要传入一下个Context对象:

@Module
public class StudentContextModule {

    private Context context;

    //此时需要你传入一个Context对象进入  
    public StudentContextModule(Context context) {
        this.context = context;
    }

    @Provides
    public String provideName() {
        return "jerry" ;
    }

    @Provides
    public int provideScore() {
        return 20 ;
    }

    //这里提供一个Context对象方法 
    @Provides
    public Context provideContext() {
        return context;
    }
}

我们桥接对象为:

@Component(modules = StudentContextModule.class)
public interface StudentContextComponent {
    void inject(StudentContextActivity activity);
}

make一下我们的项目,在数据接收容器StudentContextActivity中,这么写:

public class StudentContextActivity extends AppCompatActivity {
    @Inject
    StudentContext sContext;

    TextView tv ;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        tv = findViewById(R.id.id_tv_content);

    //这里我们就需要提供一个StudentContextModule对象
    //是的,这个对象是我们New的
        DaggerStudentContextComponent.builder().studentContextModule(new StudentContextModule(this)).build().inject(this);
    }

    public void getStudentInfo(View v) {
        tv.setText(sContext.toString());
    }
}

结果为:
关于Dagger2的一些个人理解_第10张图片
你可以看到,我们的Context对象也被传入进去了,其实就是我们的StudentContextModulenew时传入的this写入的。

依赖Module

这个意义,就相当我们每个应用中只有一个Application,我们的Activity可以依赖于这个Application,然后可以ToastSharePreference我们想要的东西。那么就来一个AppModule,全局来一个Context

@Module
public class AppModule {

    private Context context ;

    public AppModule(Context context) {
        this.context = context;
    }

    @Provides
    public Context provideContext() {
        return context;
    }

    @Provides
    public String provideGlobalName() {
        return "globalName" ;
    }

}

那么它对应的Component为:

@Component(modules = AppModule.class)
public interface AppComponent {

    /**
     * 向下提供Context
     * @return
     */
    Context getContext();

    /**
     * 向下提供Name
     * @return
     */
    String getStringName();
}

这里有一点需要声明一下,APPComponent将要被依赖,那么它需要暴露出提供初始化对象的方法,然后依赖它的Component将找不到。
好了,基类被依赖的APPComponent已经有了,现在来一个ActivityComponent,它提供了StudentContext对象方法和score对象方法。

@Module
public class ActivityModule {

    @Provides
    public StudentContext provideStudentContext(Context context,String name , int score) {
        return new StudentContext(name,score,context);
    }

    @Provides
    public int provideActivityScore() {
        return 78 ;
    }

}

那么重点来了,ActivityComponent将会依赖AppComponentAppComponent将会提供Context对象方法和name对象方法,注意dependencies关键字,它指向了依赖的对象,同时依赖的对象也是一个Component

@Component(modules = ActivityModule.class, dependencies = AppComponent.class)
public interface ActivityComponent {

    void inject(DependencyActivity activity);
}

DependencyActivity中:

public class DependencyActivity extends AppCompatActivity {

    @Inject
    StudentContext sContext;

    TextView tv ;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);

        tv  = findViewById(R.id.id_tv_content);

        //先获取AppComponent对象
        AppComponent appComponent =  DaggerAppComponent.builder().appModule(new AppModule(this)).build();

        //ActivityComponent对象将会依赖于AppComponent
        DaggerActivityComponent.
                builder().
                appComponent(appComponent).
                build().inject(this);
    }

    public void getStudentInfo(View v) {
        tv.setText(sContext.toString());
    }

}

同样我们打印结果为:
关于Dagger2的一些个人理解_第11张图片

@Name注解

主要解决同一个容器中,同时又多个相同对象需要被注入,如果你不做任何指导,那么dagger就不确定数据注入的唯一性(数据提供者 -> 数据接收者),此时有一种方法就是使用@Name注解:
还是定义一个StudentForNameAt对象,可以看到它有一个namecontext属性

public class StudentForNameAt {

    private String name ;

    private Context context;

    public StudentForNameAt(String name) {
        this.name = name;
    }

    public StudentForNameAt(Context context) {
        this.context = context;
    }

    @Override
    public String toString() {
        return "StudentForNameAt{" +
                "name='" + name + '\'' +
                ", context=" + context +
                '}';
    }
}

那么NameAtModule需要这么写:

@Module
public class NameAtModule {

    private Context context ;
    private String name ;


    public NameAtModule(Context context,String name) {
        this.context = context;
        this.name = name;
    }

    @Provides
    public Context provideContext() {
        return context;
    }

    @Named("context")  //这里使用"contex"标识
    @Provides
    public StudentForNameAt provideStudentForNameAtContext() {
        return new StudentForNameAt(context);
    }

    @Named("name")   //这里使用"name"标识
    @Provides
    public StudentForNameAt provideStudentForNameAtName(){
        return new StudentForNameAt(name);
    }

}

最后,在我们的NameAtActivity中,同时也需要@Name("name")@Name("context")标识对象的注入:

public class NameAtActivity extends AppCompatActivity {

    @Named("name")   //这里标识
    @Inject
    StudentForNameAt at1 ;

    @Named("context")  //这里标识
    @Inject
    StudentForNameAt at2 ;

    TextView tv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        tv = findViewById(R.id.id_tv_content);

        DaggerNameAtComponent.builder().nameAtModule(new NameAtModule(this,"hello world")).build().inject(this);
    }

    public void getStudentInfo(View v) {
        tv.setText(at1.toString() + "\n" + at2.toString());

    }
}

获取结果为:
关于Dagger2的一些个人理解_第12张图片
可以看到,我们的两个StudentForNameAt对象分别被注入了NameContext

当然这只是其中一种方法,还有一种方法就是自定义的Qualifier标识符。

@Qualifier 自定义标识符

@Qualifier标识符也是为了解决上面的问题,我们来同时定义一下两个注解标识符@StudentForNameStudentForScore


@Qualifier       //dagger Qualifier标识符
@Retention(RetentionPolicy.RUNTIME)  //标识为运行时状态
public @interface StudentForName {}
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface StudentForScore {
}

定义一个StudentQualifier对象,如下:

public class StudentQualifier {

    private String name ;
    private int score ;

    public StudentQualifier(){  //空的构造器 name是Tom score是77
        this.name = "Tom";
        this.score = 77 ;
    }

    public StudentQualifier(String name , int score) {
        this.name = name;
        this.score = score;
    }

    @Override
    public String toString() {
        return "StudentQualifier{" +
                "name='" + name + '\'' +
                ", score=" + score +
                '}';
    }
}

数据提供者Module为:

@Module
public class StudentQualifierModule {

    @Provides
    public String provideName(){
        return "zhangsan" ;
    }

    @Provides
    public int provideScore(){
        return 22 ;
    }

    @StudentForScore    //默认构造器被@StudentForScore修饰
    @Provides
    public StudentQualifier provideStudent(){
        return new StudentQualifier();
    }

    @StudentForName     //有参构造器被@StudentForName修饰
    @Provides
    public StudentQualifier provideStudentWithParams(String name , int score){
        return new StudentQualifier(name,score);
    }
}

然后在数据QualifierActivity接收器中:

public class QualifierActivity extends AppCompatActivity {

    TextView tv;

    @StudentForName     //被@StudentForName修饰,按道理应该是调用了有参构造器
    @Inject
    StudentQualifier qualifier1 ;

    @StudentForScore   //这个就是无参数的
    @Inject
    StudentQualifier qualifier2 ;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);

        tv = findViewById(R.id.id_tv_content);

        DaggerStudentQualifierComponent.builder().build().inject(this);
    }

    public void getStudentInfo(View v) {

        tv.setText(qualifier1.toString() + "\n" + qualifier2.toString());
    }

}

我们猜测一下结果,qualifier1应该为zhangsan22qualifier2应该为这Tom77,结果为:
关于Dagger2的一些个人理解_第13张图片
结果一致。

@PerApp and @PerActivity

我也不知道为什么,上github上看dagger写的代码,都少不了这个两个注解。如果理解了@Singleton注解的意义,那么@PerApp@PerActivity意义就差不多。上面已经说过,一个App中只有一个Applicataion,那么我们可以定义一个注解@PerApp
生命周期可以与Application一致,那么就可以理解为@PerApp修饰的方法,提供的对象在全局范围是单例的;如果定义一个@PerActivity,那么@PerActivity修饰的方法返回的对象,生命周期是与Activity是一致的。举个例子吧:
定义一个@AndroidPerApp

@Scope        //这里是@Scope 注意不是@Qualifier
@Documented  //文档标记
@Retention(RetentionPolicy.RUNTIME)
public @interface AndroidPerApp {

}

再定义一个Module,此时有个方法被@AndroidPerApp修饰:

@Module
public class AndroidPerAppModule {

    private Context context;

    public AndroidPerAppModule(Context context) {
        this.context = context ;
    }

    @Provides
    @AndroidPerApp  //标记该方法只产生一个实例 该实例的生命周期与绑定的Context生命周期一致
    public Context provideContext(){
        return context;
    }

}

此时我们的AndroidPerAppComponent

@AndroidPerApp   //AndroidPerAppModule有方法被@AndroidPerApp修饰 那么此时AndroidPerAppComponent也要被@AndroidPerApp修饰
@Component(modules = AndroidPerAppModule.class)
public interface AndroidPerAppComponent {

    /**
     * 向下提供Context
     * @return
     */
    Context getContext();
}

此时,既然是AppComponent,那么需要与App绑定了:

public class MyApp extends Application{

   //这里使用静态的 因为MyApp全局就一个   
    static AndroidPerAppComponent component ;

   @Override
   public void onCreate() {
        super.onCreate();

        component = DaggerAndroidPerAppComponent.builder().androidPerAppModule(new AndroidPerAppModule(this)).build();
    }

    public static AndroidPerAppComponent getAppComponent(){
       return component;
    }

}

那么我们可以全局调用MyApp.getAppComponent()了,这个等会再用,现在再来顶一个@PerActivity


@Scope
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface AndroidPerActivity {}

AndroidPerActivityModule中,Activity生命周期范围内,返回的数据是单例的,其实是和@Singleton作用是一致的,它并没有像市面上说的,具有和Activity相同生命周期的说法。


@Module
public class AndroidPerActivityModule {

    @AndroidPerActivity   
    @Provides
    public Student provideStudent(){
        return new Student();
    }

}

然后最重要的是PerActivityComponent了:

@AndroidPerActivity    
@Component(modules = AndroidPerActivityModule.class,
           dependencies = AndroidPerAppComponent.class)
public interface AndroidPerActivityComponent {

    void inject(AndroidAnnotationActivity activity);
}

AndroidAnnotationActivity中:

public class AndroidAnnotationActivity extends AppCompatActivity {

    @Inject
    Student st1 ;

    @Inject
    Student st2;

    TextView tv ;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        tv = findViewById(R.id.id_tv_content);
        //直接使用App.getAppComponent()获取全局的AppComponent对象
            DaggerAndroidPerActivityComponent.builder().androidPerAppComponent(MyApp.getAppComponent()).build().inject(this);
    }

    public void getStudentInfo(View v) {
        //Toast.makeText(this, "---->>" + MyApp.getAppComponent(), Toast.LENGTH_SHORT).show();

        tv.setText(st1.toString() + "--\n--" + st2.toString());
    }
}

我们此时开看一下st1st2的结果:
关于Dagger2的一些个人理解_第14张图片
可以看出,它们在AndroidAnnotationActivity范围内是单例的,这个和@Singleton注解是一致的。工作中我们会用到@PerApp,它解决了我们全局需要Context的问题。

Lazy 和 Provider

根据词义,Lazy相当于我们懒加载机制,调用了本方法才会去加载,没有调用就不加载;Provider很类似@Provides注解,但是它在的含义是每次调用都会去重复调用Module@Provides修饰的方法。举个例子:
定义一个对象类型StudentOther

public class StudentOther {
    private String name ;
    private int score ;
    private String address ;

    //初始化过程中会使用random对象 以此来模拟是否为重复创建    
    public StudentOther(Random random) {
        this.name  = "zhansgan" + random.nextDouble()  ;
        this.score  = random.nextInt(200);
        this.address = "shanghai" + random.nextGaussian();
    }

    @Override
    public String toString() {
        return "StudentOther{" +
                "name='" + name + '\'' +
                ", score=" + score +
                ", address='" + address + '\'' +
                '}';
    }
}

定义一个OtherActivityModule对象,提供了Random方法,还有两个@StudentForName@StudentForScore注解修饰的方法:

@Module
public class OtherActivityModule {

    public Random random ;

    public OtherActivityModule(){
        random  = new Random();
    }

    @Provides
    public Random provideRandom(){
        return random;
    }

    @StudentForName
    @Provides
    public StudentOther provideStudentOther(Random random){
        return new StudentOther(random);
    }

    @StudentForScore
    @Provides
    public StudentOther provideStudentOtherWidth(Random random){
        return new StudentOther(random);
    }
}

在数据接收器OtherActivity中,如下:

public class OtherActivity extends AppCompatActivity {

    @StudentForScore
    @Inject
    Lazy other;

    @StudentForName
    @Inject
    Provider other2 ;

    TextView tv;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        tv = findViewById(R.id.id_tv_content);

        DaggerOtherActivityComponent.builder().build().inject(this);
    }

    public void getStudentInfo(View v){
        StudentOther innerOther = other.get();       //调用该方法时才会去创建
        StudentOther innerOther2 = other2.get();     //调用该方法时才会去创建,但是每次都会重新加载Module中的方法 返回值有可能相同 也有可能不同

        tv.setText(innerOther.toString() + "---\n---" + innerOther2.toString());
    }
}

我们来看一下结果:
关于Dagger2的一些个人理解_第15张图片
我们可以看到innerOther始终是同一个值,而innerOther2却一直是变化的,说明每次调用Provide.get()时都去刷新了

@StudentForName
    @Provides
    public StudentOther provideStudentOther(Random random){
        return new StudentOther(random);
    }

方法。

好了,基本上总结的差不多了,文章写了很久。稍后会把代码上传一下,也算是给自己的一个交代了吧。
基本上样式如下:
关于Dagger2的一些个人理解_第16张图片

你可能感兴趣的:(Java进阶,android进阶)