Dagger2是由Google维护的Android依赖注入框架,依赖注入 (DI) 是一种在编程中广泛使用的技术,非常适合 Android 开发。
添加Dagger2
app/build.prop参考如下配置添加kapt插件和dagger依赖
// app/build.prop
plugins {
//...
id 'kotlin-android'
id 'kotlin-kapt'
//...
}
dependencies {
//...
implementation "com.google.dagger:dagger:2.x"
kapt "com.google.dagger:dagger-compiler:2.x"
//...
}常用注解
@Inject@Inject能够修饰方法、字段、构造方法,Dagger可通过此知道类的构建方式以及依赖项//当@Inject修饰构造函数时,它告诉 Dagger 如何提供该类的实例 open class Person @Inject constructor(private val context: Context) { fun showWho() { } } class MainActivity : AppCompatActivity() { //当@Inject修饰字段时,Dagger需要使用该类型的实例填充字段 //@Inject不能注解private成员 //@Inject //lateinit var mPerson: Person }@Component@Component用来修饰接口或者抽象类,Dagger需要它来创建依赖关系图@Component interface PersonComponent { //通过Inject方法,告诉Dagger请求MainActivity的注入 fun inject(activity: MainActivity) }@Module、@Binds@Module用来注释类,告诉Dagger如何提供类的实例@Binds用来告诉Dagger需要使用哪个接口实现@Module abstract class PersonalModule { @Binds abstract fun getWoman(womanPerson: WomanPerson): Person @Binds abstract fun getMan(manPerson: ManPerson): Person } class ManPerson @Inject constructor(private val context: Context) : Person(context) class WomanPerson @Inject constructor(private val context: Context) : Person(context)然后我们把
PersonModule关联到PersonComponent@Component(modules = [PersonModule::class]) interface PersonComponent { fun inject(activity: MainActivity) }此时
PersomComponent就知道PersonModule所包含的信息了@BindsInstance有时候需要提供
Context来构建类,但是Context不能被注解到,那么@BindsInstance就可以告诉Dagger在需要时提供Context实例@Component(modules = [PersonModule::class]) interface PersonComponent { fun inject(activity: MainActivity) @Component.Factory interface Factroy{ fun provideContext(@BindsInstance context: Context): PersonComponent } }通过
BuildRebuild Project构建后,Dagger就可以生成DaggerPersonComponent了,回到MainAcitivty进行依赖注入class MainActivity : AppCompatActivity() { @Inject lateinit var man:ManPerson @Inject lateinit var womanPerson: WomanPerson override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) //一步完成全部注入 DaggerPersonComponent.factory().provideContext(this).inject(this) //无需生成实例直接使用 man.showWho() womanPerson.showWho() } }通常情况下,Dagger应该在应用运行是就在内存中,会将
DaggerPersonComponent.factory().provideContext(this)放在Application中,然后在需要的时候调用之class MainApplication : Application() { val personComponent: PersonComponent by lazy { DaggerPersonComponent.factory().provideContext(this) } } class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) (application as MainApplication).personComponent.inject(this) } }@Singleton单例模式使用单例模式需要在对应的Component接口和待实例化的类前增加
@Singleton标注,即可对象的单例实例化@Singleton interface PersonComponent {/*...*/} @Singleton class ManPerson @Inject constructor(private val context: Context) : Person(context)@Subcomponent子组件子组件是继承自父组件Dagger图的组件,父组件中提供的所有对象也会在子组件中提供。这样,来自子组件的对象可以依赖于父组件提供的对象。
子组件的写法与父组件基本一致,只是需要将
@Component换成@SubComponent,在父组件中,需要指定子组件@Component(modules = [PersonalModule::class, PersonSubModule::class]) interface PersonComponent { //... fun registrationComponent(): SubComponent.Factory //... } @Subcomponent interface SubComponent { //... @Subcomponent.Factory interface Factory { fun create(): SubComponent } //... } @Module(subcomponents = [SubComponent::class]) abstract class PersonSubModule { @Binds abstract fun getPerson(person: OtherPerson):Person }Subcomponent必须由Component调用方法获取
(application as MainApplication).personComponent.registrationComponent().create()@Provides自定义实例化的方式覆盖默认实例化方式@Module abstract class PersonalModule { @Binds abstract fun getWoman(womanPerson: WomanPerson): Person @Provides fun provideWoman(context: Context):WomanPerson{ return WomanPerson(context) } }