Hilt依赖注入框架的使用介绍
引入Hilt
1. 在项目根目录的build.gradle文件中配置Hilt的插件路径:
buildscript {
...
dependencies {
...
classpath 'com.google.dagger:hilt-android-gradle-plugin:2.28-alpha'
}
}
2. 在app/build.gradle文件中,引入Hilt的插件并添加Hilt的依赖库:
...
//apply plugin: 'kotlin-kapt'
apply plugin: 'dagger.hilt.android.plugin'
android {
...
}
dependencies {
implementation "com.google.dagger:hilt-android:2.28-alpha"
//kapt "com.google.dagger:hilt-android-compiler:2.28-alpha"
}
这里同时还引入了kotlin-kapt插件,是因为Hilt是基于编译时注解来实现的,而启用编译时注解功能一定要先添加kotlin-kapt插件。如果你还在用Java开发项目,则可以不引入这个插件,同时将添加注解依赖库时使用的kapt关键字改成annotationProcessor即可
3. 在项目中启用 Java 8,请将以下代码添加到 app/build.gradle 文件中:
android {
...
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
.
.
Hilt的简单使用
使用步骤:
1. 创建MyApplication类
@HiltAndroidApp
public class MyApplication extends Application {
...
}
注:
所有使用 Hilt 的应用都必须包含一个带有 @HiltAndroidApp 注释的 Application 类
- @HiltAndroidApp : 会触发 Hilt 的代码生成操作,生成的代码包括应用的一个基类,该基类充当应用级依赖项容器
2. 将MyApplication注册到你的AndroidManifest.xml文件当中
<application
android:name=".MyApplication"
...>
</application>
3. 将依赖项注入 Android 类
@AndroidEntryPoint
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_launch);
}
}
在 Application 类中设置了 Hilt 且有了应用级组件后,Hilt 可以为带有 @AndroidEntryPoint 注释的其他 Android 类提供依赖项
Hilt 目前支持以下 Android 类:
- Application(通过使用 @HiltAndroidApp)
- Activity
- Fragment
- View
- Service
- BroadcastReceiver
注意:
在 Hilt 对 Android 类的支持方面还要注意以下几点:
Hilt 仅支持扩展 ComponentActivity 的 Activity,如 AppCompatActivity
Hilt 仅支持扩展 androidx.Fragment 的 Fragment
Hilt 不支持保留的 Fragment
4. 创建需要被注入的类
public class MyClass {
@Inject
public void MyClass(){
}
public void addLog(){
Log.d("TAG","我是需要被注入的类");
}
}
向 Hilt 提供绑定信息的一种方法是构造函数注入。在某个类的构造函数中使用 @Inject 注释,以告知 Hilt 如何提供该类的实例
注意:
- Hilt注入的字段是不可以声明成private的
补充: 如果构造函数携带参数,那么需要对参数的类也要依赖注入的相关处理;
例如 :就是MyClass的构造函数中所依赖的所有其他对象都支持依赖注入了,那么MyClass才可以被依赖注入
5. 把创建的类注入到Activity中
@AndroidEntryPoint
public class MainActivity extends AppCompatActivity {
@Inject
MyClass myclass;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_launch);
//调用MyClass里的方法
myclass.addLog();
}
}
.
.
接口的依赖注入(使用 @Binds )
1. 创建一个接口
public interface MyInterface {
//定义抽象方法
void addLog();
}
2. 创建实现接口的实体类
public class MyClass implements MyInterface {
@Inject
public void MyClass(){
}
@Override
public void addLog(){
Log.d("TAG","我是需要被注入的类");
}
}
3. 创建抽象类
@Module
@InstallIn(ActivityComponent.class)
public abstract class MyModule {
@Binds
public abstract MyInterface bindMyClass(
MyClass myclass
);
}
说明:
因为接口无法通过构造函数注入它,而没有办法向 Hilt 提供绑定信息。解决方法是在 Hilt 模块内创建一个带有 @Binds 注释的抽象函数
@Binds注释作用 :会告知 Hilt 在需要提供接口的实例时要使用哪种实现带有注释的函数会向 Hilt 提供以下信息:
函数返回类型会告知 Hilt 函数提供哪个接口的实例
函数参数会告知 Hilt 要提供哪种实现
@InstallIn(ActivityComponent.class)作用 :意味着,MyModule中的所有依赖项都可以在应用的所有 Activity 中使用
4. 把接口的实现类注入到Activity中
@AndroidEntryPoint
public class MainActivity extends AppCompatActivity {
@Inject
MyInterface myInterface;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_launch);
//调用接口实现类里的方法
myInterface.addLog();
}
}
.
.
给相同类型注入不同的实例
1. 创建一个接口
public interface MyInterface {
//定义抽象方法
void addLog();
}
2. 创建两个类
public class MyClass1 implements MyInterface {
@Inject
public void MyClass1(){
}
@Override
public void addLog(){
Log.d("TAG","我是类1");
}
}
//定义注解
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
private @interface bindMyClass1 {
}
和
public class MyClass2 implements MyInterface {
@Inject
public void MyClass2(){
}
@Override
public void addLog(){
Log.d("TAG","我是类2");
}
}
//定义注解
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
private @interface bindMyClass2 {
}
Qualifier注解作用: 给相同类型的类或接口注入不同的实例
@Retention注解作用: 用于声明注解的作用范围
注: AnnotationRetention.BINARY表示该注解在编译之后会得到保留,但是无法通过反射去访问这个注解
3. 创建抽象类
@Module
@InstallIn(ActivityComponent.class)
public abstract class MyModule {
@bindMyClass1
@Binds
public abstract MyInterface bindMyClass1(MyClass1 myclass);
@bindMyClass2
@Binds
public abstract MyInterface bindMyClass2(MyClass2 myclass);
}
@InstallIn(ActivityComponent.class)作用 :把这个模块安装到Activity组件当中
注:
Activity中包含的Fragment和View也可以使用,但是除了Activity、Fragment、View之外的其他地方就无法使用了
Hilt一共内置了7种组件类型,分别用于注入到不同的场景,如下表
使用的时候只需要替换@InstallIn(类型.class)里的类型就OK了
4. 把接口的实现类注入到Activity中
@AndroidEntryPoint
public class MainActivity extends AppCompatActivity {
@bindMyClass1
@Inject
MyInterface myInterface1;
@bindMyClass2
@Inject
MyInterface myInterface2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_launch);
//调用接口实现类里的方法
myInterface1.addLog();
myInterface2.addLog();
}
}
.
.
第三方类库的依赖注入
以Retrofit为例
1. 添加Retrofit和相关的依赖
dependencies {
// Retrofit库
implementation 'com.squareup.retrofit2:retrofit:2.0.2'
// Okhttp库
implementation 'com.squareup.okhttp3:okhttp:3.1.2'
//Gson库
implementation 'com.squareup.retrofit2:converter-gson:2.0.2'
}
2. 添加网络权限
<uses-permission android:name="android.permission.INTERNET"/>
3. 创建NetworkModule的类
@Module
@InstallIn(ActivityComponent.class)
public class NetworkModule {
@Singleton
@Provides
public static Retrofit provideRetrofit() {
return new Retrofit.Builder()
.baseUrl("请求地址的域名部分")
.addConverterFactory(GsonConverterFactory.create())
.build()
}
}
注:
provideRetrofit()这个方法名是随便定义的,Hilt不做任何要求;记得要在provideRetrofit()方法的上方加上@Provides注解,这样Hilt才能识别它
@Provides注释作用 :向 Hilt 提供以下信息:
函数返回类型会告知 Hilt 函数提供哪个类型的实例
函数参数会告知 Hilt 相应类型的依赖项
函数主体会告知 Hilt 如何提供相应类型的实例。每当需要提供该类型的实例时,Hilt 都会执行函数主体
@Singleton注解作用 :可以保证Retrofit在全局都只会存在一份实例
Hilt一共提供了7种组件作用域注解如下表所示:
使用的时候只需要把 @Singleton注解 替换到对应的注解就行了
4. 创建 接收服务器返回数据 的类
public class Users {
private String userName;
public String getUserName(){
return userName;
}
public void setUserName(String userName){
this.userName=userName;
}
}
5. 创建 用于描述网络请求 的接口
public interface GetRequest_Interface {
@GET("地址域名后的一部分")
Call<Users> getCall();
}
6. 在Activity中发起请求
@AndroidEntryPoint
public class MainActivity extends AppCompatActivity {
@Inject
Retrofit retrofit;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_launch);
//网络请求接口 的实例
GetRequest_Interface request = retrofit.create(GetRequest_Interface.class);
//对发送请求进行封装
Call<Users> call = request.getCall();
//发送网络请求(异步)
call.enqueue(new Callback<Users>() {
//请求成功时回调
@Override
public void onResponse(Call<Users> call, Response<Users> response) {
//处理返回的数据结果
response.body().show();
}
//请求失败时回调
@Override
public void onFailure(Call<Users> call, Throwable throwable) {
System.out.println("连接失败");
}
});
}
}
.
.
Hilt 中的预定义限定符(传递Context)
由于您可能需要来自应用或 Activity 的 Context 类,因此 Hilt 提供了 @ApplicationContext 和 @ActivityContext 限定符
- 获取 Activity 的上下文
public class AnalyticsAdapter {
private final Context context;
@Inject
AnalyticsAdapter(@ActivityContext Context context) {
this.context = context;
}
}
public class AnalyticsAdapter {
private final FragmentActivity activity;
@Inject
AnalyticsAdapter(FragmentActivity activity) {
this.activity = activity;
}
}
- 获取 应用上下文 的上下文
public class AnalyticsServiceImpl implements AnalyticsService {
private final Context context;
@Inject
AnalyticsAdapter(@ApplicationContext Context context) {
this.context = context;
}
}
public class AnalyticsServiceImpl implements AnalyticsService {
private final Application application;
@Inject
AnalyticsAdapter(Application application) {
this.application = application;
}
}
.
.
ViewModel的依赖注入
1. 添加依赖
dependencies {
implementation 'androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha01'
annotationProcessor 'androidx.hilt:hilt-compiler:1.0.0-alpha01'
}
2. 创建ViewModel类
public class MyViewModel extends ViewModel {
private final ExampleRepository repository;
private final SavedStateHandle savedStateHandle;
@ViewModelInject
MyViewModel(ExampleRepository repository,@Assisted SavedStateHandle savedStateHandle)
{
this.repository = repository;
this.savedStateHandle = savedStateHandle;
}
...
}
在 ViewModel 对象的构造函数中使用
@ViewModelInject
注释来提供一个 ViewModel。您还必须使用@Assisted
为SavedStateHandle
依赖项添加注释
3. 在Activity中获取ViewModel
@AndroidEntryPoint
public class MainActivity extends AppCompatActivity {
private MyViewModel ViewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ViewModel = new ViewModelProvider(this).get(MyViewModel.class);
}
...
}
.
.
WorkManager的依赖注入
1. 添加依赖
dependencies {
implementation 'androidx.hilt:hilt-work:1.0.0-alpha01'
annotationProcessor 'androidx.hilt:hilt-compiler:1.0.0-alpha01'
}
2. 创建Worker类
public class MyWorker extends Worker {
private final WorkerDependency workerDependency;
@WorkerInject
MyWorker(@Assisted @NonNull Context context,@Assisted @NonNull WorkerParameters params,WorkerDependency workerDependency) {
super(context, params);
this.workerDependency = workerDependency;
}
...
}
3. 在Application中获取MyWorker
@HiltAndroidApp
public class MyApplication extends Application implements Configuration.Provider {
@Inject HiltWorkerFactory workerFactory;
@Override
public Configuration getWorkManagerConfiguration() {
return Configuration.Builder()
.setWorkerFactory(workerFactory)
.build();
}
}