研究dagger2两天,这里结合dagger2生成的代码分析下。
component
是一个接口。
向外暴露获取实例的方法。
可以用dependencies依赖别的component,用modules包含模块。component的返回实例的方法要么在依赖的component的modules里有providers标注的方法获取,要么在自己被inject标注的构造方法获取。modules优先级比inject高。如果依赖的component里(此处指接口里的方法,无论component包含的modules里有没有)和包含的module里同时有两个方法获取一样的实例,那么会报重复绑定的错。 如果要实例化的类里有两个构造方法被inject标注,会报只能包含一个标注的错。 如果component依赖的component上有scope标注,则必须和它的scope标注一致,否则报错 如果component包含的module中的方法上有scope标注,则必须和component上的scope一致,否则报错。 编译期dagger2生成对应的实现类Dagger***component的代码。实现类里有builder内部类。利用创建者模式初始化包含的模块。如果module只有含参构造,并且这个参数不能自动注入,(可以在参数需要使用的构造方法上标注@inject以保证在注入时使用该方法,如果不标注默认使用无参构造??好像不是这样)那么在获取component时必须设置这个参数。依赖的component也必须设置注入。 依赖的component的modules中返回值为void的方法
这类方法内部实现都是这样
injector的injectMembers方法就是注入需要注入的实例以及递归注入父类的实例,直到父类不再需要注入实例为止
返回值为子组件
也就是是返回值为被SubComponent标注的接口。
这种方式跟用dependencies依赖的组件相似。
inject
Error:(19, 10) 错误: presenter.MainPresenter cannot be provided without an @Inject constructor or from an @Provides- or @Produces-annotated method.
MainActivity.mainPresenter
[injected field of type: presenter.MainPresenter mainPresenter]
如果要在一个类中用inject标注注入变量,有两种方式。
1.在这个变量的构造方法上用inject标注
2.在module中用provides标注
否则编译会报错,就是有无参构造也会报错。
module
module 类似一种工厂模式。module有的方法,component不必须有,这类方法没有暴露出去,外部拿不到实例,类似被private修饰。但component有的方法,要么必须有被providers标注的方法,要么必须有被inject标注的构造方法,这类方法外部可以拿到实例。
scope
自定义的接口。用在component 和 module中的提供实例的方法上。(能不能用在被inject标记的构造方法上?)
以系统自带的singleton为例。看代码。
看代码通过appcomponent的getContext,getNavigator等方法获取的实例实际是由providerContextProvider,provideNavigatorProvider等provider的get方法提供的。这些provider是哪里来的?(根据module中的方法名直接生成的这些类名真丑,module中的方法名应该去掉provide这个单词。。。)
看initialize方法,appmodule中被singleton标注的方法provideContext和provideNavigator由ScopeProvider.create(factory.create(module))生成provider;而没有被singleton标记的provideToastUtil直接由factory.create(module)生成provider。
再看看这两种provider的get方法有什么区别。 factory的get方法是直接返回了module里的实例化方法中注入的实例。 ScopeProvider的create方法是根据给定的factory创建一个provider。它的get方法里会判断被获取的实例有没有初始化。如果没有初始化,走factory的get方法,返回的对象即是module中方法返回的对象;如果初始化了,直接返回这个对象,不走factory的get方法。也就是说对返回的实例进行了单例处理。
看看自定义的scope和系统自带的singleton,除了类名没有区别。(默认情况下注解是不会在javadoc文档中出现的,被Documentd标注的注解会出现在文档中,对程序没影响)自定义不同的scope只是为了用不同的类名提高代码的可读性。 综上,scope的作用是对module中方法返回的对象进行指定区域内的单例处理。这个区域就是被相同scope标注的comopnent对象。module里被scope标注的方法返回的对象在同一个component实例中都是单例的。
验证结论
context1和context2_1相同是因为getContext返回的对象是application,appclication肯定只有一个。所以,我们不用scope标注,在module的方法中也可以做单例处理。
dagger2的作用是减少创建对象的重复代码,构建清晰的代码结构。
网友评论