Dagger2 独家解读
1、Dagger2是干嘛的?
Dagger2是用于依赖解耦的
2、要了解Dagger2他是怎么解耦的?
他是靠注解生成器,通过各种注解比如:@Component 、@Module、@Provides、@Named、@Singleton 等等
在AS Build阶段,使用 com.google.dagger:dagger-compiler:2.11 注解生成器,按照已经实现好的代码,对我们项目的整个代码进行扫描注解,然后获取到带有相应注解的类,然后对带有注解的类重新生成一份代码
3、那么这个代码怎么生成呢?
javapoet 就是这个代码生成工具,这个工具应该算是和注解生成器一起使用的工具了,就是这个在生成各种我们需要的源代码。
那么生成的代码分为哪几种呢?
a、Dagger***Component implements ***Component Dagger的中间桥梁 实现自我们写的 ***Component(这下应该知道为啥 Component都是接口了吧) 例如:DaggerAppComponent implements AppComponent
b、***Module_Provide***Factory Dagger创建实例方式一(通过添加了@Module的类),前面的*表示哪个 Module,后面的*代表生成的哪个实例 例如 : HttpModule_ProvideOkHttpBuilderFactory
c、***_Factory Dagger创建实例方式二(通过在构造函数上添加@Inject),*表示了创建 的实例是哪个类的
d、***_MembersInjector Component添加的 注入类 即在我们自己创建的Component里面得 返回值 为void 的方法 例如:void inject(MainActivity activity);
生成的代码大致就是这几类
其中 a属于中间件,连接b、c 与 d的
b、c属于实例创建,
d 属于实例获取 那么如果想要获取实例,只需要在对应的类中 初始化Dagger***Component的注入方法(该方法需要在自己写的***Component中自己写出来 例如:void inject(MainActivity activity);),然后在类里面使用@Inject即可
完整的如:
@Component( modules = ActivityModule.class)
public interface ActivityComponent {
void inject(MainActivity activity);
}
public class MainActivity extends AppCompatActivity{
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(this.getLayout());
DaggerActivityComponent.builder()
.build().inject(this)
}
}
4、当我们使用@Inject 获取实例时,为啥不能获取类型相同的实例?
我觉得这个就好比,同一个对象不能创建 参数类型相同的构造函数一样。
那么如何解决这个问题呢?
1、在@Module的类的方法上添加 @Named("one") 注解 进行区分
2、使用@Qualifier注解 ,创建一个注解,并使用@Qualifier 对其注解 比如 @One 将这个注解添加在 @Provides 的方法上
例如:
@Qualifier
@Documented
@Retention(RUNTIME)
public @interface One{
}
在使用时,在@Inject注解上面添加 @One 即可获取到对应的实例
上述两种方法就好比:我们创建相同参数的构造函数时,添加一个type参数,用于区分不同的对象
5、为什么我使用@Singleton 注解时,在不同的Activity使用时,是不相同的单例对象?
在Dagger2看来 @Singleton 是属于Application单例还是Activity单例呢? 其实这个和Component的创建和销毁有关,如果在Application创建和销毁那么他就是进程级别的全局单例,如果是Activity创建和销毁的,那么他就是页面级别局部单例。
还记得我们要在某一个Activity使用Dagger2吗? 是不是需要先初始化,然后再使用? 虽然我们看不到销毁,但是当页面关闭掉后,GC会自动帮我们销毁掉,所以我们在Activity使用的基本都是页面级别的局部单例。
6、我们怎么创建全局单例呢?
Dagger2也想到了这个问题,那么 Component也就出现了一个继承的关系,还有 一个SubComponent的概念。即 父Component的全局范围一定要大于子Component,我们可以写一个AppComponent (父)和 ActivityComponent(子) AppComponent在Application中创建(所有需要全局单里的对象写在该Component的Module类里面即可),ActivityComponent在具体的Activity(所有Activity要使用的对象写在该Component的Module类里面即可)页面创建即可。
在此期间,我们可以使用@Scope注解 来添加新的注解 比如 @ActivityScope 用于标记我们子Component,这个@ActivityScope是标记我们的作用域,其实用处就是告知父Component 你的子Component的作用域小于你
注意:ActivityComponent创建时,记得传入全局的Appcomponent 这样我们就可以使用全局的单例对象了
总结:
自此Dagger2的解读就到这里,其实Dagger2一直围绕的都是 创建对象-使用对象这个主线来操作的。 因为他的核心是解耦,那么他必须要有一个中间件,将创建与使用对象结合起来,那么 中间件一定要能生成对象 也一定要能将对象注入到具体的类中,而且中间件也必须是独立的。
实现了中间件功能之后,就得要扩展,比如要是有多个相同的对象不同内容的实例怎么解决,要是有多个不同的页面怎么注入,要是想注入到不同页面的对象都是单例的怎么解决? 要是想复用其他中间件的实例怎么解决?
为什么要这些扩展? 因为不扩展就没有商用的价值,后面还有java向的扩展,android向的扩展。那么Dagger2也有对应的依赖,我想基于基本功能已经实现,那么偏向android的扩展应该是如何简化使用的吧,或者更加细粒度的功能。对于这些,如果不是真正的要完全使用他的话,基本看到这里就已经足够我们使用了。