目录
- 是什么
- 为什么使用
- 基本使用
- 知识点:接口的依赖注入,第三方接口的依赖注入
一、是什么?
随着技术的更新迭代,Android端,也开始使用上了依赖注入。我也是开始要做一个新的项目,进行技术选型的时候,了解了这个技术。Hilt是一个功能强大且用法简单的依赖注入框架。
依赖注入,和后台开发用到的是一样的。从以前我们来new对象,现在变为别人帮助我们new好,我们直接使用就可以。
二、基本使用
2.1.引入依赖
implementation "com.google.dagger:hilt-android:2.44"
kapt "com.google.dagger:hilt-android-compiler:2.44"
2.2.Hilt的简单用法:类注入。
(1)加上一个@HiltAndroidApp注解,这是使用Hilt的一个必备前提
@HiltAndroidApp
class AppApplication:Application() {
}
(2)我们在Student 类的构造函数上声明了一个@Inject注解,其实就是在告诉Hilt,你可以通过这个构造函数来创建
class Student @Inject constructor(){
fun getInfo(){
Log.d("student", "getInfo: ")
}
}
(3)进行使用
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
@Inject
lateinit var student:Student
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_main3)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
student.getInfo()
}
}
Hilt一共支持6个入口点,分别是:
Application
Activity
Fragment
View
Service
BroadcastReceiver
其中,只有Application这个入口点是使用@HiltAndroidApp注解来声明的,这个我们刚才已经看过了。其他的所有入口点,都是用@AndroidEntryPoint注解来声明的。如果我们需要在这个类里面进行依赖注入,就需要使用到这个注解。
@Inject注解,表示我希望通过Hilt来注入student这个字段。
三、知识点
3.1 接口的依赖注入
interface CollectService {
@GET("lg/collect/list/{page}/json")
suspend fun getCollectList(@Path("page") page: Int): BaseModel<Collect>
}
@AndroidEntryPoint
class MainActivity : BaseActivity<HomeActivityMainBinding, MainViewModel>() {
@Inject
lateinit var mApi: CollectService
}
那么这个实例是哪里来的呢?如下:
@Module //声明一个@Module注解,表示这一个用于提供依赖注入实例的模块。
@InstallIn(SingletonComponent::class)//ilt 这个模块中定义的依赖项将被安装在应用程序的全局单例组件中。这意味着这些依赖项将在整个应用程序的生命周期内只被创建一次,并在所有需要它们的地方共享。
class DIHomeNetServiceModule {
/**
* Home模块的[HomeApiService]依赖提供方法
*
* @param retrofit Retrofit
* @return HomeApiService
*/
@Singleton//@Singleton 注解也用于 provideDatabase 方法上,以确保返回的 AppDatabase 实例是单例的。
@Provides//表示provideHomeApiService方法是一个提供依赖项的方法
fun provideHomeApiService(retrofit: Retrofit): HomeApiService {
return retrofit.create(HomeApiService::class.java)
}
}
@HiltViewModel是什么意思
@HiltViewModel 是 Hilt 库中的一个注解,它用于 Android 开发中,特别是在使用 ViewModel 架构组件时。ViewModel 是 Android Jetpack 架构组件的一部分,旨在存储和管理界面相关的数据。ViewModel 的主要目的是在配置更改(如屏幕旋转)期间保持数据。
然而,ViewModel 需要通过某种方式被实例化并注入到 Fragment 或 Activity 中。在不使用依赖注入框架(如 Hilt)的情况下,这通常是通过 ViewModelProvider 来手动完成的。但是,使用 Hilt 可以使这个过程更加简洁和自动化。
@HiltViewModel 注解的作用是将 ViewModel 标记为可以由 Hilt 管理的依赖项。当你将 @HiltViewModel 注解添加到 ViewModel 类上时,Hilt 会自动处理 ViewModel 的创建和注入过程。这样,你就不需要手动调用 ViewModelProvider 来获取 ViewModel 实例了。
下面是一个使用 @HiltViewModel 注解的简单示例:
import androidx.lifecycle.ViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
@HiltViewModel
class MyViewModel @Inject constructor(
// 可以在这里注入其他依赖项
private val someDependency: SomeDependency
) : ViewModel() {
// ViewModel 的内容
}
在这个例子中,MyViewModel 被标记为 @HiltViewModel,这意味着它将被 Hilt 管理。构造函数被标记为 @Inject,这样 Hilt 就可以知道在创建 MyViewModel 实例时需要注入哪些依赖项(在这个例子中是 SomeDependency)。
然后,在 Fragment 或 Activity 中,你可以使用 Hilt 提供的 by viewModels() 委托来获取 ViewModel 的实例,而无需手动调用 ViewModelProvider:
import androidx.fragment.app.Fragment
import dagger.hilt.android.AndroidEntryPoint
import androidx.lifecycle.viewModelScope
@AndroidEntryPoint
class MyFragment : Fragment() {
private val myViewModel: MyViewModel by viewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// 使用 myViewModel ...
}
}
请注意,为了使 by viewModels() 委托工作,你需要在 Fragment 或 Activity 上添加 @AndroidEntryPoint 注解,这样 Hilt 才能知道这个类是一个需要注入依赖项的入口点。
viewModels()的构造函数的示例是如何传递进去的。自己传递,Hilt回去自动注入。
3.2 第三方的依赖注入
如何给第三方的类进行依赖注入呢?按照前面的流程,我们需要给类加上@Inject来选择要创建实例的方式。这个时候要借助@Module注解了
/**
* 全局作用域的网络层的依赖注入模块
*/
@Module
@InstallIn(SingletonComponent::class)
class DINetworkModule {
/**
* [OkHttpClient]依赖提供方法
*
* @return OkHttpClient
*/
@Singleton
@Provides
fun provideOkHttpClient(): OkHttpClient {
// 日志拦截器部分
val level = if (BuildConfig.VERSION_TYPE != VersionStatus.RELEASE) BODY else NONE
val logInterceptor = HttpLoggingInterceptor().setLevel(level)
return OkHttpClient.Builder()
.connectTimeout(15L * 1000L, TimeUnit.MILLISECONDS)
.readTimeout(20L * 1000L, TimeUnit.MILLISECONDS)
.addInterceptor(logInterceptor)
.retryOnConnectionFailure(true)
.build()
}
/**
* 项目主要服务器地址的[Retrofit]依赖提供方法
*
* @param okHttpClient OkHttpClient OkHttp客户端
* @return Retrofit
*/
@Singleton
@Provides
fun provideMainRetrofit(okHttpClient: OkHttpClient): Retrofit {
return Retrofit.Builder()
.baseUrl(NetBaseUrlConstant.MAIN_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient)
.build()
}
}
provideMainRetrofit和provideMainRetrofit()这个函数名是随便定义的,Hilt不做任何要求。
这次我们写的不是抽象函数了,而是一个常规的函数。在这个函数中,按正常的写法去创建OkHttpClient的实例,并进行返回即可。
函数的上方加上@Provides注解,这样Hilt才能识别它。
可以注意到 provideMainRetrofit(okHttpClient: OkHttpClient)的okHttpClient是谁传递?答案是,完全不需要传递,因为这个过程是由Hilt自动完成的。我们所需要做的,就是保证Hilt能知道如何得到一个OkHttpClient的实例,而这个工作我们早在前面一步就已经完成了。