jetPack组件必学#Dagger2&Hilt

35 阅读6分钟

jetPack组件必学#Lifecycle

jetPack组件必学#LiveData&ViewMode

jetPack组件必学#DataBinding

jetPack组件必学#Dagger2&Hilt

jetPack组件必学#Navigation

jetPack组件必学#Room

一.Dagger使用攻略

1.Dagger2是什么?

Dagger2是Dagger的升级版,是一个依赖注入框架,第一代由大名鼎鼎的Square公司共享出来,第二代则是由谷歌接手后推出的,现在由Google接手维护,传送门Dagger2的GitHub地址

2.为什么使用Dagger2?

上面我们说到,Dagger2是一个依赖注入框架,那什么是依赖注入呢,可以抽象的理解为其实就是将一个类里面包含另外一个类实例的引用。

我们常用的在属性,方法中参数 ,甚至通过接口中抽象方法中的参数等方式都可以实现依赖注入,那为什么还要使用Dagger2呢,当然如果是单兵作战,项目不大的话,不用也没关系,但是在项目很大,协同工作中,建议还是使用Dagger2,因为你会发现它会让你的项目结构清晰,维护起来也更加方便,降低代码耦合度,另外它是编译时生成一些代码,也不会产生性能影响。

3.Dagger2的基本使用

1.常用注解

@Component注入的纽带,关联注入的@Inject和@Modulue依赖
@Module提供对象的工厂
@ProvidesModule中提供对象的方法注解
@Inject需要注入的成员或者构造方法的注解
@Named限定注解 注解在@Inject和@Provider上
@Singleton作用域单例
@Scope作用域注解

2.对象注入

通过@Component 注解纽带和@Module对象工厂类提供对象,在通过@Inject注解在需要注入的对象上面:

class MainActivity : AppCompatActivity() {
    @Named("debug")
    @Inject
    lateinit var userDebug: User

    @Named("release")
    @Inject
    lateinit var userRelease: User

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        DaggerUserComponent.create().inject(this)
        println("userDebug:$userDebug,userRelease:$userRelease")
        TestA().init()
        TestB().init()

    }
}
@Module
class UserModule {

    /**
     * @Named 限定对象
     * @return User
     */
    @Named("release")
    @Provides
    fun userRe(): User {
        println("release--->>>")
        return User()
    }
    @Named("debug")
    @Provides
    fun userDe(): User {
        println("debug--->>>")
        return User()
    }

}

3.限定注入

我们通过@Name注解注入,如上面的代码示例中对User的注入

4.作用域与单例

我们的单例通常是通过@Singleton这个scope注解来标识,但是它这个通常是当前注入的component中的,比如我们在上述module中注入一个okHttp对象:

@Singleton //单例scope
@Component(modules = [UserModule::class])
interface UserComponent {

    fun inject(mainActivity: MainActivity)

    fun inject(testA: TestA)

    fun inject(testA: TestB)
}
@Module
class UserModule {

    /**
     * @Named 限定对象
     * @return User
     */
    @Named("release")
    @Provides
    fun userRe(): User {
        println("release--->>>")
        return User()
    }
    @Named("debug")
    @Provides
    fun userDe(): User {
        println("debug--->>>")
        return User()
    }

   @Singleton //单例标记
   @Provides
   fun OkHttp3():OkHttpClient{
       println("UserModule single OkHttp--->>>")
       return OkHttpClient.Builder().build()
   }
}

我们在使用时:

class TestA {

    @Inject
    lateinit var okHttpClient: OkHttpClient
    @Inject
    lateinit var okHttpClient1: OkHttpClient
    fun init(){
        DaggerUserComponent.create().inject(this)
        println("TestA okHttpClient:$okHttpClient,okHttpClient1: $okHttpClient1")
    }
}

class TestB {
    @Inject
    lateinit var okHttpClient: OkHttpClient
    @Inject
    lateinit var okHttpClient1: OkHttpClient
    fun init(){
        DaggerUserComponent.create().inject(this)
        println("TestB okHttpClient:$okHttpClient,okHttpClient1: $okHttpClient1")
    }
}

我们看下打印:

UserModule single OkHttp--->>>
TestA okHttpClient:okhttp3.OkHttpClient@af98bb8,okHttpClient1: okhttp3.OkHttpClient@af98bb8
UserModule single OkHttp--->>>
TestB okHttpClient:okhttp3.OkHttpClient@d22bd91,okHttpClient1: okhttp3.OkHttpClient@d22bd91

可以看到,这个单例并不是全局单例,而是需要被注入的具体对象中的单例,比如在MainActivity中它是单例的,在TwoActivity中它也是个单例。那这种全局单例如何实现呢?我们通过会提供一个AppComponent,在其中提供单例,然后让其他需要这个单例的继承自这个component,并且使用其内部自己的scope,因为dependencies关系的component之间的scope是不能相同的

@Singleton
@Component(modules = [AppModule::class])
interface AppComponent {
    fun okHttp(): OkHttpClient //单例
}

@Module
class AppModule {
    
    @Singleton
    @Provides
    fun OkHttp3(): OkHttpClient {
        println("AppModule single OkHttp--->>>")
        return OkHttpClient.Builder().build()

    }
}

class App : Application() {

    @Inject
    lateinit var appComponent: AppComponent //提供appComponent
    override fun onCreate() {
        super.onCreate()
        appComponent = DaggerAppComponent.create()
    }

}

//需要全局单例的容器 继承自AppComponent
@ActivityScope
@Component(modules = [UserModule::class], dependencies = [AppComponent::class])
interface UserComponent {

    fun inject(mainActivity: MainActivity)

    fun inject(testA: TestA)

    fun inject(testA: TestB)
}

class MainActivity : AppCompatActivity() {
    @Named("debug")
    @Inject
    lateinit var userDebug: User

    @Named("release")
    @Inject
    lateinit var userRelease: User

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
//        DaggerUserComponent.create().inject(this)
//        DaggerUserComponent.builder().build()
//            .inject(this)
        DaggerUserComponent.builder().appComponent((application as App).appComponent)
            .build().inject(this)
        println("userDebug:$userDebug,userRelease:$userRelease")
//        TestA().init()
//        TestB().init()

         TestA().init((application as App).appComponent)
        TestB().init((application as App).appComponent)
    }
}

//自定义的scope
@Scope
@Documented
@Retention(AnnotationRetention.RUNTIME)
 annotation class ActivityScope {
}

class TestA {

    @Inject
    lateinit var okHttpClient: OkHttpClient
    @Inject
    lateinit var okHttpClient1: OkHttpClient
    fun init(){
        //DaggerUserComponent.create().inject(this)
        DaggerUserComponent.builder().build().inject(this)
        println("TestA okHttpClient:$okHttpClient,okHttpClient1: $okHttpClient1")
    }

    fun init(appComponent: AppComponent){
        DaggerUserComponent.builder().appComponent(appComponent).build().inject(this)
        println("TestA okHttpClient:$okHttpClient,okHttpClient1: $okHttpClient1")
    }
}
class TestB {

    @Inject
    lateinit var okHttpClient: OkHttpClient
    @Inject
    lateinit var okHttpClient1: OkHttpClient
    fun init(){
        //DaggerUserComponent.create().inject(this)
        DaggerUserComponent.builder().build().inject(this)
        println("TestB okHttpClient:$okHttpClient,okHttpClient1: $okHttpClient1")
    }

    fun init(appComponent: AppComponent){
        DaggerUserComponent.builder().appComponent(appComponent).build().inject(this)
        println("TestB okHttpClient:$okHttpClient,okHttpClient1: $okHttpClient1")
    }
}

日志打印:

TestA okHttpClient:okhttp3.OkHttpClient@af98bb8,okHttpClient1: okhttp3.OkHttpClient@af98bb8
TestB okHttpClient:okhttp3.OkHttpClient@af98bb8,okHttpClient1: okhttp3.OkHttpClient@af98bb8

可以看到,它是全局唯一的单例。

5.懒加载Lazy和Provider

懒加载是注入对象时,在使用时才会获取帮助我们去实例化,Lazy对象获取的是单例,Provider不是单例。

import dagger.Lazy
import javax.inject.Provider
@Named("release")
@Inject
lateinit var userRelease1: Lazy<User>
 @Named("release")
 @Inject
 lateinit var userRelease2: Provider<User>

6.技术要点

1.注解迷失:在component中,需要被注入的类不可使用多态

2.继承关系的component中的scope不可相同,如app中的单例和activity中的scope

3.singleton单例注解生命周期依附于component

4.component关联的modules中不能有重复的provides,也就是关联的多个module不能提供相同的对象。

5.Dagger2 依赖查找的顺序是先查找 Module 内所有的 @Provides 提供的依赖,如果查找不到再去查找 @Inject 提供的依赖。


二.Hilt的使用攻略

hilt是基于Dagger2开发的,专用于android的依赖注入插件,提供专属API,使用起来 更简单。

1.hilt配置

在app的gradle中配置

    //hilt插件配置
   //hilt
    id("kotlin-kapt")
    id("com.google.dagger.hilt.android") // 添加 Hilt 插件
    //hilt
   implementation("com.google.dagger:hilt-android:2.48")
    kapt("com.google.dagger:hilt-compiler:2.48")

在项目的gradle中配置插件

buildscript{
    dependencies{
        //hilt插件
        classpath("com.google.dagger:hilt-android-gradle-plugin:2.48")
    }
}

2.使用攻略

Hilt是基于Dagger2的,他在使用时和Dagger2的主要区别是可以省去Componenet的编写,我们来看下它是如何注入的:

//1.app中标记
@HiltAndroidApp
class App : Application() {

}
//2.表示Module使用的范围 这里注入到Activity中的Module
@InstallIn(ActivityComponent::class)
@Module
class UserModule {

    @Provides
    fun providerUser():User{
        println("create User--->>>")
        return User()
    }
}
//3.注入到Activity中
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {

    @Inject
    lateinit var user: User
    @Inject
    lateinit var user2: User
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        println("hilt user:$user,user2:$user2")
    }
}

1.Activity级别单例

//表示Module使用的范围 这里注入到Activity中的Module
@InstallIn(ActivityComponent::class)
@Module
class UserModule {

    @ActivityScoped //Activity级别的单例
    @Provides
    fun providerUser():User{
        println("create User--->>>")
        return User()
    }
}

2.App级别的单例

//(Dagger ≥ 2.31使用SingletonComponent)
@InstallIn(SingletonComponent::class) 
@Module
class AppModule {

    @Singleton // 表示应用级别的全局单例
    @Provides
    fun OkHttp3(): OkHttpClient {
        println("AppModule single OkHttp--->>>")
        return OkHttpClient.Builder().build()

    }
}

3.接口注入实列



interface Service {

    fun dosth()
}

//构造方法需要标记
class ServiceImpl  @Inject constructor(@ActivityContext val context: Context): Service {
    override fun dosth() {
        println("ServiceImpl :$context")
    }


}

class ServiceImpl1 @Inject constructor( @ActivityContext val context: Context):Service {
    override fun dosth() {
        println("ServiceImpl1 context:$context")
    }

@InstallIn(ActivityComponent::class)
@Module
abstract class ServiceModule{

    //标记接口 跳入实现类
    @ServiceQualifier //标记不同的实现类
    @Binds
    abstract  fun provideService(serviceImpl: ServiceImpl):Service

    @Service1Qualifier
    //标记接口 跳入实现类
    @Binds
    abstract  fun provideService2(serviceImpl: ServiceImpl1):Service
 }
@Qualifier
@Retention(AnnotationRetention.RUNTIME)
annotation class ServiceQualifier

@Qualifier
@Retention(AnnotationRetention.RUNTIME)
annotation class Service1Qualifier


  @ServiceQualifier
    @Inject
    lateinit var serviceImpl: Service
    @Service1Qualifier
    @Inject
    lateinit var serviceImpl1: Service

4.作用域绑定关系

Component范围CreatedDestroyed
SingletonComponent@SingletonApplication#onCreate(Application#onDestroy()
ActivityRetainedComponent@ActivityRetainedScopeActivity#onCreate()Activity#onDestroy()
ActivityComponent@ActivityScopedActivity#onCreate()Activity#onDestroy()
FragmentComponent@FragmentScopedFragment#onAttach()Fragment#onDestroy()
ViewComponent@ViewScopedView#super()View destroyed
ViewWithFragmentComponent@ViewScopedView#super()View destroyed
ServiceComponent@ServiceScopedService#onCreate()Service#onDestroy()

常用的绑定关系:

组件类型 对应生命周期 示例依赖项

SingletonComponent用于Application 全局单例,常见的Retrofit、数据库等

ActivityComponent 用于每个Activity 独立常见的当前 Activity 的共享依赖

ViewModelComponent用于每个 ViewModel 独立 常见的仓库、业务类

FragmentComponent用于每个 Fragment 独立,当前 Fragment 的依赖

三.Dagger2和Hilt的区别