相关资料
https://developer.android.com/codelabs/android-hilt?hl=zh-cn#11
https://developer.android.com/training/dependency-injection/hilt-android
https://blog.csdn.net/guolin_blog/article/details/109787732
项目引用
注意: 同时使用 Hilt 和数据绑定的项目需要 Android Studio 4.0 或更高版本
项目的根级 build.gradle添加
buildscript {
...
dependencies {
...
classpath 'com.google.dagger:hilt-android-gradle-plugin:2.28-alpha'
}
}
然后,应用 Gradle 插件并在 app/build.gradle
文件中添加以下依赖项:
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"
}
Hilt 使用 Java 8 功能,将以下代码添加到 app/build.gradle
文件中:
android {
...
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
注解关键字
@HiltAndroidApp
使用在Application上,不用就报错
@AndroidEntryPoint
使用在要注入的地方的类上
@InstallIn
作用在Module上,标明作用域范围。
@Inject
用在要注入的类的构造参数上
@Binds
标记抽象方法, 返回接口类型, 实现是方法的唯一参数.
@Named
别名,基本用于接口多实现/多构造参数时候
@Provides
用在方法上, 提供返回值类型的依赖,
@Singleton
单例
@Qualifier
用在注解上,注解用来区分要提供的参数
@Module
用在类上,标记这是一个module. 在Kotlin代码中, module可以是一个Object.
@ViewScoped
用于提供对象的方法上,标识为作用于view范围
@ServiceScoped
用于提供对象的方法上,标识为作用于Service范围
@FragmentScoped
用于提供对象的方法上,标识为作用于Fragment范围
@ActivityScoped
用于提供对象的方法上,标识为作用于Activity范围
@ActivityRetainedScoped
用于提供对象的方法上,标识为作用于ViewModle
@ActivityContext
内置的Activity类型Context,当做参数的时候会默认提供一个ActivityContext,而不用再传参
@ApplicationContext
内置的Application类型Context,当做参数的时候会默认提供一个Application 类型的Context,而不用再传参
注解使用
@HiltAndroidApp
使用hilt首先要在Application上添加 不然会报错
Hilt Activity must be attached to an @AndroidEntryPoint Application.
@HiltAndroidApp
public class HiltDemoApp extends Application {
}
@AndroidEntryPoint
@AndroidEntryPoint 添加在要注入类的对象顶部,不添加直接报null指针错误。
@AndroidEntryPoint
public class MainActivity extends AppCompatActivity {
@Inject
Man man;
}
@Inject
@Inject 用的地方有两处。如下
- 用在要注入对象里,就是告知 要注入哪个构造参数 用来实例化
public class Man implements IPerson {
@Inject
public Man() {
}
@Override
public void say() {
}
}
- 在注入的页面里或者对象里 代表我要注入一个该类型对象
@AndroidEntryPoint
public class MainActivity extends AppCompatActivity {
@Inject
IPerson man;
}
@Binds
官网说 标记抽象方法, 返回接口类型, 实现是方法的唯一参数。我总结如下
-
用在modle里
-
作用在抽象方法上
-
返回你传入的参数类型,也就是参数括号里传啥返回啥
-
返回值如果是接口的时候,则该接口只有一个实现。 在使用的地方可以直接用 xxx接口 对象的方法中注入如下。
@Binds
abstract IPerson getWoMan( Woman man);
@Inject
IPerson woman;
如果返回值是接口,且有多个实现的时候,那么需要处理。需要添加一个注解进行区分,下面注解部分会详细说。或者使用@Named(“xxx”)进行区分
@ManTag
@Binds
abstract IPerson getMan( Man man);
@WoManTag
@Binds
abstract IPerson getWoMan( Woman man);
@ManTag
@Inject
IPerson man;
@WoManTag
@Inject
IPerson woman;
@Module
对外提供对象
@Module 使用场景有两种
@Binds 和@ Provides
注意事项
-
@Binds和@Provides不能放在同一个module里.
-
@Provides和@Inject冲突
-
@Named和@自定义注释效果一样
-
使用@Binds Modle 类是个抽象类,方法是抽象方法,传参是要返回的对象类型
-
使用@Provides Modle 类不能是抽象类
-
使用 @Module 必须 使用 @InstallIn添加使用范围
使用@Module 个人认为大部分为了解决下面几个问题
-
对象构造带参数/多构造
-
返回值为接口,实现对象唯一
-
返回值为接口 但是接口实现不唯一
-
返回对象 不能直接new,比如三方对象
@Binds 基础用法 接口单实现
IPerson 是一个接口 当前只有Man类实现,这么写注入正常。对了记得在Man 构造添加 @Inject
//Module
@Module
@InstallIn(ActivityComponent.class)
abstract class PersonModel {
@Binds
abstract IPerson getMan( Man man);
}
//注入
@Module
@InstallIn(ActivityComponent.class)
abstract class PersonModel {
@Binds
abstract IPerson getMan( Man man);}
public class Man implements IPerson {
//记得添加@Inject
@Inject
public Man() {
}
@Override
public void say() {
}
}
当 IPerson 多实现的时候,我们只对外提供Man,上面代码还不会有问题,但是我们添加Woman的提供时候,就有问题了。代码如下。其实想想也是,多实现,你直接接口注入,谁知道要Man还是Woman
//Iperson 多实现的时候
public class Woman implements IPerson {
public Woman() {
}
@Override
public void say() {
}
}
// 添加对外提供woMan方法
@Module
@InstallIn(ActivityComponent.class)
abstract class PersonModel {
//提供Man
@Binds
abstract IPerson getMan( Man man);
//提供Woman
@Binds
abstract IPerson getWoMan( Woman man);
}
//注入点
@AndroidEntryPoint
public class MainActivity extends AppCompatActivity {
@Inject
IPerson person;}
解决方案
@Named("xxx")
//利用@Named区分
@Module
@InstallIn(ActivityComponent.class)
abstract class PersonModel {
@Named("Man")
@Binds
abstract IPerson getMan( Man man);
@Named("Woman")
@Binds
abstract IPerson getWoMan( Woman man);
}
//注入 利用@Named区分
@AndroidEntryPoint
public class MainActivity extends AppCompatActivity {
@Named("Man")
@Inject
IPerson man;
@Named("Woman")
@Inject
IPerson woMan;}
@自定义注解 这里 会用到@Qualifier
定义两个注解,在注入的时候添加。
其实自定义注解和@Named 其实就是起别名操作方式。看个人需求选择吧
//ManTag
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@interface ManTag {
}
//WoManTag
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@interface WoManTag {
}
//注入
@AndroidEntryPoint
public class MainActivity extends AppCompatActivity {
@ManTag
@Inject
IPerson man;
@WoManTag
@Inject
IPerson woMan;}
@Provides
适宜用情况
-
多构造参数(无法通过构造函数注入)
-
接口多实现
-
某个类不归自己所有,类无法直接创建(Retrofit、
OkHttpClient
或Room 数据库这种)
注意:
-
带参数的就不要带@Inject了,Inject在多构造参数的时候会报错。
-
使用Provides @Moulde 类不能是抽象类
小tips:
-
函数返回类型会告知 Hilt 函数提供哪个类型的实例。
-
函数参数会告知 Hilt 相应类型的依赖项。
-
函数主体会告知 Hilt 如何提供相应类型的实例。每当需要提供该类型的实例时,Hilt 都会执行函数主体。
在@Provides上 也可以用@Named 区分具体注入类型, 也可以使用自定义注解
//我们给Woman添加一个带参的构造 注意 用@Provides 构造就不用加@Inject了
public class Woman implements IPerson {
public Woman() {
}
public Woman(String name) {
}
@Override
public void say() {
}
}
//module
@Module
@InstallIn(ActivityComponent.class)
public class ProvideModel {
//返回Man类型
@Provides
@ManTag
public IPerson getMan() {
return new Man();
}
//返回Woman无参构造
@WoManTag
@Provides
public IPerson getManName() {
return new Woman();
}
//返回Woman 带参构造
@WoManNameTag
@Provides
public IPerson getWoManByName() {
return new Woman("lili");
}
//返回第三方对象
@Provides
public static OkHttpClient getOkHttp() {
return new OkHttpClient();
}
}
//注入点
@AndroidEntryPoint
public class MainActivity extends AppCompatActivity {
@ManTag
@Inject
IPerson man;
@WoManTag
@Inject
IPerson woMan;
@WoManNameTag
@Inject
IPerson woManName;
@Inject
OkHttpClient okHttpClient;
}
@InstallIn
@InstallIn()括号里类类的范围
* ApplicationComponent
* ActivityComponent.class
* ActivityRetainedComponent.class
* FragmentComponent.class
* ServiceComponent.class
* ViewComponent.class
* ViewWithFragmentComponent.class
如名字所见,当前module作用范围 可以是整个Application,也可以是某个view。ActivityRetainedComponent.class很特殊,对应是ViewModle。
如何限定提供的对象的使用范围,如下。
scopes
@ViewScoped
@ServiceScoped
@FragmentScoped
@ActivityScoped
@ActivityRetainedScoped
//作用范围在activity 同理切换就可以了
@ActivityScoped
@WoManTag
@Provides
public IPerson getManName() {
return new Woman();
}
下面几张图是我截取的官网的图,可以看下作用域,和上下级绑定,生命周期等
组件的作用域注释
image.png
组件默认绑定
image.png
image.png
组默认绑定
image.png
组件生命周期
image.png
作用域
image.png
@Singleton
单例,当作用域@Module中的时候,要求@InstallIn后面跟的必须是ApplicationComponent.class。其实想想也是,单例生命周期和APP同样长。
导入Context
当需要的参数包含Contxt的时候,Hilt内部提供如下Contenxt ,作为参数传入即可。
-
@ApplicationContext
-
@ActivityContext
注意事项:如果@InstallIn 添加的是ActivityComponent.class ,
下面@Provides 里是@ApplicationContext,会报错。当前module中有@Singleton 则@InstallIn 那里肯定要是ApplicationComponent.class 。下面@Provides 写@ActivityContext 也会报错 。@InstallIn和Context 要统一级别。
给WoMan添加一个需要context的参数
public class Woman implements IPerson {
public Woman(Context context, String name) {
}
@Override
public void say() {
}
}
//module中 这么提供就可以了 系统会自动填充一个Context
@Module
@InstallIn(ActivityComponent.class)
public class ProvideModel {
@WoManContextTag
@Provides
public IPerson getWoManByContext(@ActivityContext Context context) {
return new Woman(context, "lili");
}
}
viewModel
依赖
implementation 'androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha01'
// When using Kotlin.
kapt 'androidx.hilt:hilt-compiler:1.0.0-alpha01'
// When using Java.
annotationProcessor 'androidx.hilt:hilt-compiler:1.0.0-alpha01'
代码 @ViewModelInject和@Assisted
//使用 @ViewModelInject
public class HiltViewModel extends ViewModel {
@ViewModelInject
public HiltViewModel() {
}
public void getData(){};
}
//@Assisted
@ViewModelInject
public HiltViewModel(@Assisted SavedStateHandle savedStateHandle) {
}
//使用
@AndroidEntryPoint
public class MainActivity extends AppCompatActivity {
private HiltViewModel hiltViewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
hiltViewModel =new ViewModelProvider(this).get(HiltViewModel.class);
hiltViewModel.getData();
}}
WorkManger
依赖
implementation 'androidx.hilt:hilt-work:1.0.0-alpha01'
// When using Kotlin.
kapt 'androidx.hilt:hilt-compiler:1.0.0-alpha01'
// When using Java.
annotationProcessor 'androidx.hilt:hilt-compiler:1.0.0-alpha01'
注意
在 Worker 对象的构造函数中使用 @WorkerInject 注释来注入一个 Worker。您只能在 Worker 对象中使用 @Singleton 或未限定作用域的绑定。您还必须使用 @Assisted 为 Context 和 WorkerParameters 依赖项添加注释:
@HiltAndroidApp
public class HiltDemoApp extends Application implements Configuration.Provider {
@Inject
HiltWorkerFactory workerFactory;
@NonNull
@NotNull
@Override
public Configuration getWorkManagerConfiguration() {
return new Configuration.Builder().setWorkerFactory(workerFactory).build();
}
}
//感觉work 使用率还是比较低的
public class HiltWorkManger extends Worker {
private static final String TAG = "HiltWorkManger";
@WorkerInject
public HiltWorkManger(@Assisted @NonNull @NotNull Context context, @Assisted @NonNull @NotNull WorkerParameters workerParams) {
super(context, workerParams);
}
@NonNull
@NotNull
@Override
public Result doWork() {
return Result.success();
}
}
@EntryPoint
其实这个@EntryPoint 个人不是搞的很明白,但是感觉使用概率不高
看代码和注释
// @InstallIn
//@EntryPoint 注入点 要注意是接口 返回你要注入的对象
public class EntryModel {
@InstallIn(ActivityComponent.class)
@EntryPoint
public interface IEntryPointModel {
DemoEntry getEntry();
}
}
//注入的对象 要注入的构造要有@Inject
public class DemoEntry {
private String name;
@Inject
public DemoEntry() {
}
public String getName() {
return "9999";
}
public void setName(String name) {
this.name = name;
}
}
//注入点 EntryPointAccessors 是个关键点
//EntryPointAccessors 通过接口 调用返回的注入对象
@AndroidEntryPoint
public class MainActivity extends AppCompatActivity {
@Inject
DemoEntry demoEntry;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
this.demoEntry = EntryPointAccessors.fromActivity(this, IEntryPoint.class).getDemoEntry();
}}
image.png