1、依赖版本
依赖版本,这里注意和老版本不同,无需再集成ViewModel拓展依赖了
implementation 'com.google.dagger:hilt-android:2.38.1'
kapt 'com.google.dagger:hilt-android-compiler:2.38.1'
根目录依赖插件
//Hilt插件
classpath 'com.google.dagger:hilt-android-gradle-plugin:2.38.1'
运行模块加入插件
apply plugin: 'dagger.hilt.android.plugin'
2、入口定义
Application还是要定义注解
@HiltAndroidApp
class MyApplication : BaseApplication() {
}
3、单例的定义
单例的定义和老版本有所不同
/**
* 全局的DI注入
*/
@Module
@InstallIn(SingletonComponent::class)
class ApplicationModule {
//如果是自己定义的MyApplication,通过一个Module向下转型
@Provides
fun provideMyApplication(application: Application): MyApplication {
return application as MyApplication
}
//全局的Gson 使用框架进行容错处理
@Provides
@Singleton
fun provideGson(): Gson {
return GsonFactory.getSingletonGson()
}
}
使用单例也非常简单,直接注入,它会自己去Scope中一层一层往上找。
@AndroidEntryPoint //如果有东西注入必加的注解
class UserLoginActivity : YYBaseVDBActivity<UserLoginViewModel, ActivityUserLoginBinding>() {
@Inject //直接注入-一层一层找ActivityScope中找不到 就去ApplicationScop中找 就找到上面定义的那个Gson提供者了
lateinit var mGson: Gson
}
4、ViewModel的注入
Repository:
@Singleton //构造方法注入 并保持单例
class DemoRepository @Inject constructor() : BaseRepository() {
suspend inline fun getIndustry(): OkResult<List<Industry>> {
// xxx
}
}
@Singleton //构造方法注入 并保持单例
class SchoolRepository @Inject constructor() : BaseRepository() {
suspend inline fun getSchool(): OkResult<List<SchoolBean>> {
//xxx
}
}
ViewModel:
@HiltViewModel
class UserLoginViewModel @Inject constructor(
private val mRepository: DemoRepository,
private val mSchoolRepository: SchoolRepository, //通过构造方法注入 会自动去找上面的@Inject的构造对象 初始化出来
private val savedStateHandle: SavedStateHandle //系统的类 帮助Activity重建保存和恢复状态用的 也是自动注入的
private val application: Application //新版本Application是可以直接使用的
) : BaseViewModel() {
}
Activity
@AndroidEntryPoint
class UserLoginActivity : BaseActivity>() {
private val viewModel : UserLoginViewModel by viewModels() //通过此委托方法可以直接获取ViewModel对象
//private val viewModel by viewModels<UserLoginViewModel>() 和上面的一样效果
@Inject
lateinit var mGson: Gson
}
5、自定义对象的注入
自定义对象的注入也是比较常用的,比如Adapter,自定义View,Layout等。
分为简单类注入和复杂类注入。
简单类注入直接构造方法Inject就可以了
@Singleton
class UserDao @Inject constructor(
//3.找到这里 发现这个构造是空参数 直接构造并完成返回
) {
fun printUser(): String {
return this.toString()
}
}
@Singleton
class UserServer @Inject constructor(
private val userDao: UserDao //2.找到这里,发现这个构造需要一个UserDao对象,继续查找
) {
fun testUser() {
YYLogUtils.w(userDao.printUser())
toast(userDao.printUser())
}
fun getDaoContent(): String {
return userDao.printUser()
}
}
@AndroidEntryPoint
class UserLoginActivity : YYBaseVDBActivity<UserLoginViewModel, ActivityUserLoginBinding>() {
@Inject
lateinit var userServer: UserServer //1.由这里开始发起查找
}
复杂类的注入,我们可以定义Module
public class Pencil {
public void sayPencil() {
YYLogUtils.w("Pencil - i'm pencil");
}
}
public class Book {
private Pencil pencil;
public Book(Pencil pencil) {
this.pencil = pencil;
}
public void sayBook() {
YYLogUtils.w("Book:" + this.toString());
pencil.sayPencil();
}
}
开始注入的中间类,这个是Activity中的生命周期保持单例,如果想全局保持单例 需要@InstallIn(SingletonComponent::class) @Singleton注解方法。
这样虽然复杂一点但是更灵活了
@Module
@InstallIn(ActivityComponent::class)
class AuthDIModel {
@ActivityScoped
@Provides
fun providePencil(): Pencil { //Activity级别同一个实例
return Pencil()
}
@Provides
fun provideBook(pencil: Pencil): Book { //找到这里的时候 发现需要一个Pencil 然后再去找Pencil
return Book(pencil)
}
}
使用:
@AndroidEntryPoint
class UserLoginActivity : YYBaseVDBActivity<UserLoginViewModel, ActivityUserLoginBinding>() {
@Inject
lateinit var userServer: UserServer //和下面是两种不同的注入方式 都可以
@Inject
lateinit var mBook: Book //一样的可以用
}
6、接口对象的注入
上面的几种注入方式,已经含括了绝大部分场景,另一种比较少见的是接口的实现注入,也是分2中类型,一种是接口单实例的注入和接口多实例的注入
单实例注入:
interface IBook {
suspend fun saveBook(name: String)
suspend fun getBookAllSum(): Int
}
class BookImpl @Inject constructor() : IBook {
@Inject
lateinit var dao: BookDao
override suspend fun saveBook(name: String) {
//这里可能会有一些自己的处理...
dao.insertAll(Book(name))
}
override suspend fun getBookAllSum(): Int {
return dao.queryBookAll()
}
}
注意这里的 @Module 这里的Class是抽象类,提供实例的注解是 @Binds 而不是 @Provides
@InstallIn(ApplicationComponent::class)
@Module
abstract class BookModel {
@Binds
abstract fun bindIBook(impl: BookImpl): IBook //直接指定到单实例上面
}
使用
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
@Inject
lateinit var iBook: IBook
}
多实例的注入:
如果是一个接口的多实例,如何注入呢?
interface Engine {
fun start()
fun shutdown()
}
多实例:
class GasEngine() @Inject constructor() : Engine {
override fun start() {
println("Gas engine start.")
}
override fun shutdown() {
println("Gas engine shutdown.")
}
}
class ElectricEngine() @Inject constructor() : Engine {
override fun start() {
println("Electric engine start.")
}
override fun shutdown() {
println("Electric engine shutdown.")
}
}
当然要定义标识的自定义注解来标识他们啦 不然怎么知道谁是谁。
当然还有别的方式来标识,这里只是推荐使用这种方式
@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class BindGasEngine
@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class BindElectricEngine
和上面的Mudule一样,只是标识了自定义注解标识
@Module
@InstallIn(ActivityComponent::class)
abstract class EngineModule {
@BindGasEngine
@Binds
abstract fun bindGasEngine(gasEngine: GasEngine): Engine //直接指定到对应的实例上
@BindElectricEngine
@Binds
abstract fun bindElectricEngine(electricEngine: ElectricEngine): Engine //直接指定到对应的实例上
}
使用
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
@BindGasEngine //指定标识
@Inject
lateinit var gasEngine: Engine
@BindElectricEngine //指定标识
@Inject
lateinit var electricEngine: Engine
}
看到这里是不是觉得Hilt的使用其实也不难,我们在Android的开发场景中,也就用到这些功能,其实都是模板代码,大家可以选择对应的场景复制到自己的项目中改一下相关的对象就可以了。
网友评论