相關(guān)資料
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
項(xiàng)目引用
注意: 同時(shí)使用 Hilt 和數(shù)據(jù)綁定的項(xiàng)目需要 Android Studio 4.0 或更高版本
項(xiàng)目的根級 build.gradle添加
buildscript {
...
dependencies {
...
classpath 'com.google.dagger:hilt-android-gradle-plugin:2.28-alpha'
}
}
然后布持,應(yīng)用 Gradle 插件并在 app/build.gradle
文件中添加以下依賴項(xiàng):
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
}
}
注解關(guān)鍵字
@HiltAndroidApp
使用在Application上届慈,不用就報(bào)錯(cuò)
@AndroidEntryPoint
使用在要注入的地方的類上
@InstallIn
作用在Module上捌显,標(biāo)明作用域范圍奏窑。
@Inject
用在要注入的類的構(gòu)造參數(shù)上
@Binds
標(biāo)記抽象方法, 返回接口類型, 實(shí)現(xiàn)是方法的唯一參數(shù).
@Named
別名哗伯,基本用于接口多實(shí)現(xiàn)/多構(gòu)造參數(shù)時(shí)候
@Provides
用在方法上, 提供返回值類型的依賴讥蔽,
@Singleton
單例
@Qualifier
用在注解上,注解用來區(qū)分要提供的參數(shù)
@Module
用在類上画机,標(biāo)記這是一個(gè)module. 在Kotlin代碼中, module可以是一個(gè)Object.
@ViewScoped
用于提供對象的方法上冶伞,標(biāo)識為作用于view范圍
@ServiceScoped
用于提供對象的方法上,標(biāo)識為作用于Service范圍
@FragmentScoped
用于提供對象的方法上步氏,標(biāo)識為作用于Fragment范圍
@ActivityScoped
用于提供對象的方法上响禽,標(biāo)識為作用于Activity范圍
@ActivityRetainedScoped
用于提供對象的方法上,標(biāo)識為作用于ViewModle
@ActivityContext
內(nèi)置的Activity類型Context,當(dāng)做參數(shù)的時(shí)候會默認(rèn)提供一個(gè)ActivityContext荚醒,而不用再傳參
@ApplicationContext
內(nèi)置的Application類型Context,當(dāng)做參數(shù)的時(shí)候會默認(rèn)提供一個(gè)Application 類型的Context芋类,而不用再傳參
注解使用
@HiltAndroidApp
使用hilt首先要在Application上添加 不然會報(bào)錯(cuò)
Hilt Activity must be attached to an @AndroidEntryPoint Application.
@HiltAndroidApp
public class HiltDemoApp extends Application {
}
@AndroidEntryPoint
@AndroidEntryPoint 添加在要注入類的對象頂部,不添加直接報(bào)null指針錯(cuò)誤界阁。
@AndroidEntryPoint
public class MainActivity extends AppCompatActivity {
@Inject
Man man;
}
@Inject
@Inject 用的地方有兩處侯繁。如下
- 用在要注入對象里,就是告知 要注入哪個(gè)構(gòu)造參數(shù) 用來實(shí)例化
public class Man implements IPerson {
@Inject
public Man() {
}
@Override
public void say() {
}
}
- 在注入的頁面里或者對象里 代表我要注入一個(gè)該類型對象
@AndroidEntryPoint
public class MainActivity extends AppCompatActivity {
@Inject
IPerson man;
}
@Binds
官網(wǎng)說 標(biāo)記抽象方法, 返回接口類型, 實(shí)現(xiàn)是方法的唯一參數(shù)泡躯。我總結(jié)如下
用在modle里
作用在抽象方法上
返回你傳入的參數(shù)類型贮竟,也就是參數(shù)括號里傳啥返回啥
返回值如果是接口的時(shí)候,則該接口只有一個(gè)實(shí)現(xiàn)较剃。 在使用的地方可以直接用 xxx接口 對象的方法中注入如下咕别。
@Binds
abstract IPerson getWoMan( Woman man);
@Inject
IPerson woman;
如果返回值是接口,且有多個(gè)實(shí)現(xiàn)的時(shí)候写穴,那么需要處理惰拱。需要添加一個(gè)注解進(jìn)行區(qū)分,下面注解部分會詳細(xì)說啊送〕ザ蹋或者使用@Named("xxx")進(jìn)行區(qū)分
@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
注意事項(xiàng)
@Binds和@Provides不能放在同一個(gè)module里.
@Provides和@Inject沖突
@Named和@自定義注釋效果一樣
使用@Binds Modle 類是個(gè)抽象類,方法是抽象方法馋没,傳參是要返回的對象類型
使用@Provides Modle 類不能是抽象類
使用 @Module 必須 使用 @InstallIn添加使用范圍
使用@Module 個(gè)人認(rèn)為大部分為了解決下面幾個(gè)問題
對象構(gòu)造帶參數(shù)/多構(gòu)造
返回值為接口昔逗,實(shí)現(xiàn)對象唯一
返回值為接口 但是接口實(shí)現(xiàn)不唯一
返回對象 不能直接new,比如三方對象
@Binds 基礎(chǔ)用法 接口單實(shí)現(xiàn)
IPerson 是一個(gè)接口 當(dāng)前只有Man類實(shí)現(xiàn)披泪,這么寫注入正常纤子。對了記得在Man 構(gòu)造添加 @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() {
}
}
當(dāng) IPerson 多實(shí)現(xiàn)的時(shí)候搬瑰,我們只對外提供Man,上面代碼還不會有問題款票,但是我們添加Woman的提供時(shí)候,就有問題了泽论。代碼如下艾少。其實(shí)想想也是,多實(shí)現(xiàn)翼悴,你直接接口注入缚够,誰知道要Man還是Woman
//Iperson 多實(shí)現(xiàn)的時(shí)候
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);
}
//注入點(diǎn)
@AndroidEntryPoint
public class MainActivity extends AppCompatActivity {
@Inject
IPerson person;}
解決方案
@Named("xxx")
//利用@Named區(qū)分
@Module
@InstallIn(ActivityComponent.class)
abstract class PersonModel {
@Named("Man")
@Binds
abstract IPerson getMan( Man man);
@Named("Woman")
@Binds
abstract IPerson getWoMan( Woman man);
}
//注入 利用@Named區(qū)分
@AndroidEntryPoint
public class MainActivity extends AppCompatActivity {
@Named("Man")
@Inject
IPerson man;
@Named("Woman")
@Inject
IPerson woMan;}
@自定義注解 這里 會用到@Qualifier
定義兩個(gè)注解,在注入的時(shí)候添加幔妨。
其實(shí)自定義注解和@Named 其實(shí)就是起別名操作方式〉危看個(gè)人需求選擇吧
//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
適宜用情況
多構(gòu)造參數(shù)(無法通過構(gòu)造函數(shù)注入)
接口多實(shí)現(xiàn)
某個(gè)類不歸自己所有误堡,類無法直接創(chuàng)建(Retrofit、
OkHttpClient
或Room 數(shù)據(jù)庫這種)
注意:
帶參數(shù)的就不要帶@Inject了雏吭,Inject在多構(gòu)造參數(shù)的時(shí)候會報(bào)錯(cuò)。
使用Provides @Moulde 類不能是抽象類
小tips:
函數(shù)返回類型會告知 Hilt 函數(shù)提供哪個(gè)類型的實(shí)例杖们。
函數(shù)參數(shù)會告知 Hilt 相應(yīng)類型的依賴項(xiàng)悉抵。
-
函數(shù)主體會告知 Hilt 如何提供相應(yīng)類型的實(shí)例。每當(dāng)需要提供該類型的實(shí)例時(shí)摘完,Hilt 都會執(zhí)行函數(shù)主體姥饰。
在@Provides上 也可以用@Named 區(qū)分具體注入類型, 也可以使用自定義注解
//我們給Woman添加一個(gè)帶參的構(gòu)造 注意 用@Provides 構(gòu)造就不用加@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無參構(gòu)造
@WoManTag
@Provides
public IPerson getManName() {
return new Woman();
}
//返回Woman 帶參構(gòu)造
@WoManNameTag
@Provides
public IPerson getWoManByName() {
return new Woman("lili");
}
//返回第三方對象
@Provides
public static OkHttpClient getOkHttp() {
return new OkHttpClient();
}
}
//注入點(diǎn)
@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
如名字所見孝治,當(dāng)前module作用范圍 可以是整個(gè)Application,也可以是某個(gè)view列粪。ActivityRetainedComponent.class很特殊,對應(yīng)是ViewModle谈飒。
如何限定提供的對象的使用范圍篱竭,如下。
scopes
@ViewScoped
@ServiceScoped
@FragmentScoped
@ActivityScoped
@ActivityRetainedScoped
//作用范圍在activity 同理切換就可以了
@ActivityScoped
@WoManTag
@Provides
public IPerson getManName() {
return new Woman();
}
下面幾張圖是我截取的官網(wǎng)的圖步绸,可以看下作用域掺逼,和上下級綁定,生命周期等
組件的作用域注釋
組件默認(rèn)綁定
組默認(rèn)綁定
組件生命周期
作用域
@Singleton
單例瓤介,當(dāng)作用域@Module中的時(shí)候吕喘,要求@InstallIn后面跟的必須是ApplicationComponent.class。其實(shí)想想也是刑桑,單例生命周期和APP同樣長氯质。
導(dǎo)入Context
當(dāng)需要的參數(shù)包含Contxt的時(shí)候,Hilt內(nèi)部提供如下Contenxt ,作為參數(shù)傳入即可祠斧。
@ApplicationContext
@ActivityContext
注意事項(xiàng):如果@InstallIn 添加的是ActivityComponent.class ,
下面@Provides 里是@ApplicationContext闻察,會報(bào)錯(cuò)。當(dāng)前module中有@Singleton 則@InstallIn 那里肯定要是ApplicationComponent.class 琢锋。下面@Provides 寫@ActivityContext 也會報(bào)錯(cuò) 辕漂。@InstallIn和Context 要統(tǒng)一級別。
給WoMan添加一個(gè)需要context的參數(shù)
public class Woman implements IPerson {
public Woman(Context context, String name) {
}
@Override
public void say() {
}
}
//module中 這么提供就可以了 系統(tǒng)會自動填充一個(gè)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 對象的構(gòu)造函數(shù)中使用 @WorkerInject 注釋來注入一個(gè) Worker吴超。您只能在 Worker 對象中使用 @Singleton 或未限定作用域的綁定钉嘹。您還必須使用 @Assisted 為 Context 和 WorkerParameters 依賴項(xiàng)添加注釋:
@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
其實(shí)這個(gè)@EntryPoint 個(gè)人不是搞的很明白,但是感覺使用概率不高
看代碼和注釋
// @InstallIn
//@EntryPoint 注入點(diǎn) 要注意是接口 返回你要注入的對象
public class EntryModel {
@InstallIn(ActivityComponent.class)
@EntryPoint
public interface IEntryPointModel {
DemoEntry getEntry();
}
}
//注入的對象 要注入的構(gòu)造要有@Inject
public class DemoEntry {
private String name;
@Inject
public DemoEntry() {
}
public String getName() {
return "9999";
}
public void setName(String name) {
this.name = name;
}
}
//注入點(diǎn) EntryPointAccessors 是個(gè)關(guān)鍵點(diǎn)
//EntryPointAccessors 通過接口 調(diào)用返回的注入對象
@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();
}}