本文属代码GG原创,非经本人同意,制止转载。
github地址:https://github.com/luxiaoming/dagger2Demo
需要交换,联系微信:code_gg_boy
更多精彩,时时关注微信公众号code_gg_home
没有更多开场白,直接说下我对它的理解。
Dagger2 是1个Android依赖注入框架。而android开发当前非常流行的非MVP模式莫属了,Dagger2的目标便是将MVP中的V P 进1步解耦,到达模块化最大的解耦,使得代码更容易保护。
举个栗子:有个A对象 B对象 和C对象,如果C对象创建需要A和B,那末我们是否是需要构造里面传入参数A和参数B,然后在使用的地方以下写个代码:
C c=new C(new A(),new B());
如果我们使用了Dagger2时候,我们就不需要管这些了,只需要关联住能提供创建A 和 B的地方 ,然后在需要C的地方写下:
@Inject
C c;
然后在这个类的初始化地方进行注入便可。
我们初步来看,会发现Dagger2优势不大,没甚么吸引人的,那末请你静下心来,看完再得出结论。
闲话休叙,我们来直接上代码:(常规写法)
public class Test3 {
public Test3() {
}
}
public class MainActivity extends AppCompatActivity {
Test3 test3;
@Override
protected void onCreate(Bundle savedInstanceState) {
//.....
test3 = new Test3();
}
}
使用了注解方式,使得Dagger2能找到它。
public class Test3 {
//这里可以看到加入了注解方式
@Inject
public Test3() {
}
}
@Singleton
//用这个标注标识是1个连接器
@Component()
public interface MainActivityComponent {
//这个连接器要注入的对象。这个inject标注的意思是,我后面的参数对象里面有标注为@Inject的属性,这个标注的属性是需要这个连接器注入进来的。
void inject(MainActivity activity);
}
public class MainActivity extends AppCompatActivity {
//加入注解,标注这个test3是需要注入的
@Inject
Test3 test3;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//使用组件进行构造,注入
DaggerMainActivityComponent.builder().build().inject(this);
}
这是最简单的1种使用了。首先我们看到,第1印象是我去,这个更复杂了啊。我只能说确切,由于这个是它对的最基础的使用,看起来很笨拙,但是当它在大型项目里面,在依赖更多的情况下,则会产生质的奔腾,会发现它非常好用,并且将你需要传递的参数都隐藏掉,来实现解耦。
我先说下Dagger2的注释思路:关键的点是@Component,这个是个连接器,用来连接提供方和使用方的,所以它是桥梁。它使用在组件里面标记使用的Module(标记用到了哪一个Module,主要是看使用方需要哪些对象进行构造,然后将它的提供方@module写在这里) 然后我们写入1个void inject(MainActivity activity); 这里后面的参数,就是我们的使用方了。如此1来,我们在使用的地方,使用类似这类方式(DaggerMainActivityComponent.builder().build().inject(this);)的动作,将使用方类里面的标记 为@Inject的类初始化掉,完成自动初始化的动作。
结构以下:
为了更好的来学习它,我们来顺次看看各种使用情况。
直接感受下,如何?
我们来看1个代码段,当我们创建两个实例的时候,发现地址是独立的。
如果我们想要1样的地址呢?加上1句话,具体以下:
效果便是两个共用实例啦。
将提供的构造,放入@module里面,具体效果以下:
去掉标记的@singleton后
效果变成独立的啦
有时我们需要依赖1个组件,这个最多见的用法是,我们App实例里面提供了比如获得sharepreference的实例,和比如现在代码里面的LocationManager的实例,我们Activity里面需要这些实例,我们该如何来做呢?看效果:
1:1个AndroidModule 模块标记
这个模块属于AndroidcationComponent 组件里面
这里有个关键点,就是子组件需要这个里面的某个实例的时候,这里需要使用1个接口,将需要的实例做1个返回动作。这里是LocationManager这1行。
我们的子组件的代码以下:
对应的Cmodule代码以下:
再来看下Test3的代码当前情况:
使用的地方:
仔细的你会发现这里多了1个注释了,@PerActivity,它是个甚么鬼呢?
这里我们看到它是使用了@Scope的1个注释,这个注释的意思就是作用域,在作用域内保持单例,可以直接理解为单例便可。
为何要新增1个呢,主要是由于各个组件需要独立出来,因此如果是依赖关系,则需要各自在不同的注释作用域里面。
我们来看下在Cmodule里面,加上@perActivity注释后的效果:
如果去掉呢?
我们突然发现,它和单例的注释起的作用1样啊。so。。。是否是发现甚么啦。
因此我们得出1个结论,这里@Singleton
就是1个普通的作用域通道,使用了作用域@Scope注释的代码,会变成单例模式。为了验证我们的思路,作以下测试:
我们将之前的@Singleton用新建的这个替换掉,验证两次的生成代码,发现1模1样,1模1样,1模1样,so。。。 就是这个模样啦。
为何要自定义标记呢?这个标记不是使用@Scope注释的哦,是使用@Qualifier 标记的,它的目标是,为了辨别如果同时返回类型1样,比如构造男孩,女孩的基本属性,性别和名字时候,获得男孩和女孩都是1个对象,我们该如何辨别呢,这个就是关键啦。说这么多,真心很烦,直接栗子来啦。
这里稍安勿躁,先来看相同效果的另外一个注释,@Name,这个是Dagger2自带的1个让辨别,效果以下:
这里@Name可以简单的1个使用方式,就是它不是辨别对象,而是限制使用时候必须加入这个注释,否则报错,目的就是让使用者注意是不是使用正确了。
我们使用自己的注释再来1遍:
对照两种方式,我们发现使用@Name的时候,后面的注释名字会敲错,而我们第2种方式呢,则不会耶,so。。。
我们看下自定义的标记,作为限制出错,让强迫标注的例子。
这个出现的目的是为了如果有1个组件,是每次创建实例提供给他人,而恰好其他组件(有多个)里面有需要它,如果只有1个,我们就用依赖弄定啦。那末它就能够定义成子组件,谁需要在谁的组件里面加1下,具体看例子:
如上,写完啦。。
实战地方,可以参照 https://github.com/gzsll/TLint 来浏览啦,收工。
需要交换,联系微信:code_gg_boy
更多精彩,时时关注微信公众号code_gg_home
上一篇 为什么清浮动?清浮动的方法是什么?哪一种是终极方法?
下一篇 异步下载照片墙