IOC
IOC(Inversion of Control)
是原来由程序代码中主动获取的资源,转变由第三方获取并使原来的代码被动接收的方式,以达到解耦的效果,称为控制反转
这种注入方式,也是共享内存的一种方式。

基本配置
参考官网配置 github 上官网dagger
我们自己在这里用
implementation 'com.google.dagger:dagger:2.4'
annotationProcessor 'com.google.dagger:dagger-compiler:2.4'
使用逻辑

module:用于提供对象
component:用于组织module并进行注入
基本使用
1. 提供用于注入的对象
package top.zcwfeng.daggersample.data
class HttpObject {
}
package top.zcwfeng.daggersample.data
class DatabaseObject {
}
2. 编写Module
/**
* 用来提供对象
*/
//@Singleton
@Module
class HttpModule {
//@Singleton
@Provides
fun providerHttpObject():HttpObject{
return HttpObject()
}
}
3. 编写Component, Kotlin的语法表示
//@Singleton
@Component(modules = [HttpModule::class,DatabaseModule::class])
interface MyComponent {
// 这里不能用多态,父类不行
fun injectMainActivity(mainActivity: MainActivity2)
fun injectSecondActivity(secondActivity:SecondActivity)
}
4. 注入到Activity
class MainActivity2 : AppCompatActivity() {
@Inject
lateinit var httpObject1:HttpObject
@Inject
lateinit var httpObject2:HttpObject
...
}
5.rebuild项目让APT生成需要的文件
6.在需要注入的类中使用
MainActivity2 补充
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main2)
// 语法1
DaggerMyComponent.create().injectMainActivity(this)
DaggerMyComponent.builder().httpModule(HttpModule())
.databaseModule(DatabaseModule())
.build()
.injectMainActivity(this)
Log.e("httpObject1",httpObject1.toString())
Log.e("httpObject2",httpObject2.toString())
}
7. 单利使用
将之前的Component,HttpModule 的 @Singleton 注释打开,就是单利的使用
看下输出
Log.e("httpObject1",httpObject1.toString())
Log.e("httpObject2",httpObject2.toString())
>>>>
2021-01-09 15:07:28.079 16769-16769/top.zcwfeng.daggersample E/httpObject1: top.zcwfeng.daggersample.data.HttpObject@20e7e14
2021-01-09 15:07:28.079 16769-16769/top.zcwfeng.daggersample E/httpObject2: top.zcwfeng.daggersample.data.HttpObject@20e7e14
我们在SecondActivity中在次写同样方法,MainActivity2 跳转到SecondActivity
class SecondActivity : AppCompatActivity() {
@Inject
lateinit var httpObject:HttpObject
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_second)
// 语法1
DaggerMyComponent.create().injectSecondActivity(this)
DaggerMyComponent.builder().httpModule(HttpModule())
.databaseModule(DatabaseModule())
.build()
.injectSecondActivity(this)
Log.e("httpObject",httpObject.toString() + "--sec")
}
}
输出
2021-01-09 22:54:35.087 17385-17385/top.zcwfeng.daggersample E/httpObject1: top.zcwfeng.daggersample.data.HttpObject@f024075
2021-01-09 22:54:35.087 17385-17385/top.zcwfeng.daggersample E/httpObject2: top.zcwfeng.daggersample.data.HttpObject@f024075
2021-01-09 22:55:10.804 17385-17385/top.zcwfeng.daggersample E/httpObject: top.zcwfeng.daggersample.data.HttpObject@ca20d--sec
注意:以上单例只能在注入类中局部有效
为什么会一致量httpObject1和httpObject2,我们查看
DaggerMyComponent.builder().httpModule(HttpModule())
.databaseModule(DatabaseModule())
.build()
.injectMainActivity(this)
build 源码
build()->DaggerMyComponent#initialize--->DoubleCheck#provider
我们看到DoubleCheck 实现了Provider的接口get(),
@Override
public T get() {
Object result = instance;
if (result == UNINITIALIZED) {
synchronized (this) {
result = instance;
if (result == UNINITIALIZED) {
instance = result = provider.get();
/* Null out the reference to the provider. We are never going to need it again, so we
* can make it eligible for GC. */
provider = null;
}
}
}
return (T) result;
}
调到SecondActivity 后provider不是一个对象,所以单例对象不是一个是一个新对象。
全局单例
class DaggerApp: Application() {
//lateinit var appComponent:AppComponent
lateinit var myComponent:MyComponent
override fun onCreate() {
super.onCreate()
//appComponent = DaggerAppComponent.create()
myComponent = DaggerMyComponent.builder()
.httpModule(HttpModule())
.databaseModule(DatabaseModule())
.build()
}
}
MainActivity2 中 注入就可以
// 全局singleton
(application as DaggerApp).myComponent.injectMainActivity(this)
SecondActivity 中同样直接注入
(application as DaggerApp).myComponent.injectSecondActivity(this)
输出
2021-01-10 16:09:55.916 20488-20488/top.zcwfeng.daggersample E/httpObject1: top.zcwfeng.daggersample.data.HttpObject@f024075
2021-01-10 16:09:55.917 20488-20488/top.zcwfeng.daggersample E/httpObject2: top.zcwfeng.daggersample.data.HttpObject@f024075
2021-01-10 16:10:28.741 20488-20488/top.zcwfeng.daggersample E/httpObject: top.zcwfeng.daggersample.data.HttpObject@f024075--sec
所以全局单例,我们可以放Application中进行build,全局使用
8. 多个COMPONENT组合依赖
dagger2不能使用多个Component同时注入同一个类中
这种情况需要进行Component的组合
举个例子,我们再写一个注入实例还是注入到MainActivity2:
package top.zcwfeng.daggersample.dagger.demo2.di
class Presenter {
}
------
package top.zcwfeng.daggersample.dagger.demo2.di
import dagger.Module
import dagger.Provides
@Module
class PresenterModule {
@Provides
fun providePresenter():Presenter{
return Presenter()
}
---------
package top.zcwfeng.daggersample.dagger.demo2.di
import dagger.Component
import top.zcwfeng.daggersample.MainActivity2
@Component(modules = [PresenterModule::class])
open interface PresenterComponent {
fun inject(mainActivity: MainActivity2)
}
》》》》编译后报错
错误: top.zcwfeng.daggersample.data.HttpObject cannot be provided without an @Inject constructor or from an @Provides- or @Produces-annotated method.
public abstract void inject(@org.jetbrains.annotations.NotNull()
^
top.zcwfeng.daggersample.data.HttpObject is injected at
top.zcwfeng.daggersample.MainActivity2.httpObject1
top.zcwfeng.daggersample.MainActivity2 is injected at
top.zcwfeng.daggersample.dagger.demo2.di.PresenterComponent.inject(mainActivity)[WARN] Incremental annotation processing requested, but support is disabled because the following processors are not incremental: dagger.internal.codegen.ComponentProcessor (NON_INCREMENTAL).
这个时候我们需要更换能听多个Component同时注入到一个类。
PresenterComponent 这个时候需要修改成下面:
@Component(modules = [PresenterModule::class])
open interface PresenterComponent {
// 之前如果有注入过Component进入MainActivity2 同时多个会报错
// 需要更改写法
// fun inject(mainActivity: MainActivity2)
fun providerPresenter():Presenter;
}
在 MyComponent中添加depencies 进行组合
@Singleton
@Component(modules = [HttpModule::class,DatabaseModule::class]
,dependencies = [PresenterComponent::class])
interface MyComponent {
// 这里不能用多态,父类不行
fun injectMainActivity(mainActivity: MainActivity2)
fun injectSecondActivity(secondActivity:SecondActivity)
}
在使用的时候,看下我们DaggerApp中的onCreate
override fun onCreate() {
super.onCreate()
appComponent = DaggerAppComponent.create()
myComponent = DaggerMyComponent.builder()
.httpModule(HttpModule())
.databaseModule(DatabaseModule())
.presenterComponent(DaggerPresenterComponent.create())
.build()
}
在MainActivity2 注入表示层
....
@Inject
lateinit var presenter: Presenter
....
//验证打印
Log.e("presenter", presenter.toString())
....
去掉所有的@Singleton 运行验证
2021-01-10 17:47:11.266 21989-21989/top.zcwfeng.daggersample E/httpObject1: top.zcwfeng.daggersample.data.HttpObject@317480a
2021-01-10 17:47:11.266 21989-21989/top.zcwfeng.daggersample E/httpObject2: top.zcwfeng.daggersample.data.HttpObject@a98e87b
2021-01-10 17:47:11.266 21989-21989/top.zcwfeng.daggersample E/presenter: top.zcwfeng.daggersample.dagger.demo2.di.Presenter@412a698
把之前的@Singleton 加回来再次运行看一下
2021-01-10 18:01:00.511 22378-22378/top.zcwfeng.daggersample E/httpObject1: top.zcwfeng.daggersample.data.HttpObject@a98e87b
2021-01-10 18:01:00.511 22378-22378/top.zcwfeng.daggersample E/httpObject2: top.zcwfeng.daggersample.data.HttpObject@a98e87b
2021-01-10 18:01:00.511 22378-22378/top.zcwfeng.daggersample E/presenter: top.zcwfeng.daggersample.dagger.demo2.di.Presenter@412a698
如果这个时候想要新家入得PresenterComponent 想要使用单例,那么加入@Signeton标记就会报错,如何解决,我们只能采用自定义方式。
自定义Scope
@Scope
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
annotation class UserScope{
}
@Scope
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
annotation class AppScope{
}
MyComponent 相关的我们,加上@AppScope,PresenterComponent 相关我们加上@UserScope。
输出配置
MainActivity2----->
@Inject
lateinit var httpObject1: HttpObject
@Inject
lateinit var httpObject2: HttpObject
@Inject
lateinit var presenter: Presenter
@Inject
lateinit var presenter2: Presenter
。。。
Log.e("httpObject1", httpObject1.toString())
Log.e("httpObject2", httpObject2.toString())
Log.e("presenter", presenter.toString())
Log.e("presenter", presenter.toString())
》》》输出结果
2021-01-10 18:29:15.578 22743-22743/top.zcwfeng.daggersample E/httpObject1: top.zcwfeng.daggersample.data.HttpObject@a98e87b
2021-01-10 18:29:15.578 22743-22743/top.zcwfeng.daggersample E/httpObject2: top.zcwfeng.daggersample.data.HttpObject@a98e87b
2021-01-10 18:29:15.578 22743-22743/top.zcwfeng.daggersample E/presenter: top.zcwfeng.daggersample.dagger.demo2.di.Presenter@412a698
2021-01-10 18:29:15.578 22743-22743/top.zcwfeng.daggersample E/presenter: top.zcwfeng.daggersample.dagger.demo2.di.Presenter@412a698
总结一下思路:
1》dependencies用法
- 1.为每个Component定义自己的Scope
@Scope
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
annotation class UserScope{
}
@Scope
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
annotation class AppScope{
}
- 进行依赖
@AppScope
@Component(modules = {HttpModule.class, DatabaseModule.class}
,dependencies = {PresenterComponent.class})
public interface MyComponent {
//不能用多态
void injectMainActivity(MainActivity mainActivity);
void injectSecActivity(SecActivity secActivity);
}
- 初始化使用
DaggerMyComponent.builder()
.httpModule(new HttpModule())
.databaseModule(new DatabaseModule())
.presenterComponent(DaggerPresenterComponent.create())
.build();
- dependencies注意事项
scope&dependencies的使用
1.多个component上面的scope不能相同
2.没有scope的组件不能去依赖有scope的组件
2》@Subcomponent用法
- subcomponet
@Subcomponent(modules = {TestSubModule.class})
public interface TestSubComponent {
void injectMainActivity(MainActivity activity);
}
- Component
@Component(modules = {MainModule.class})
public interface MainComponent {
TestSubComponent getTestSubComponent();
}
- 使用
DaggerMainComponent.create()
.getTestSubComponent()
.injectMainActivity(this);
这种用法不是很灵活
9. 其他用法
1》带参数module
@Module
public class MainModule {
/***
* 构造方法需要其他参数时候
*
* @return
*/
@Provides
B providerB() {
return new B();
}
@Provides
A providerA(B b) {
return new A(b);
}
}
module 中
module中:
@Named("key1")
@Provides
public User provideUser(){
return new User("David","123");
}
@Named("key2")
@Provides
public User provideUser2(){
return new User("David","456");
2》@Named使用
注入点:
@Named("key1")
@Inject
User user1;
@Named("key2")
@Inject
User user2;
通过以上语法,就可以实现两个不同的key注入不一样的同类型对象
3》lazy 和 Provider
这种方式是在get的时候,才初始化需要注入的对象
声明
@Inject
Lazy<A> lazy;
@Inject
Provider<A> provider;
测试
Log.i(TAG,lazy.get().hashCode()+"");
Log.i(TAG,provider.get().hashCode()+"");
网友评论