android Jetpack-Hilt基礎(chǔ)入門

相關(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)建(RetrofitOkHttpClient 或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)的圖步绸,可以看下作用域掺逼,和上下級綁定,生命周期等

組件的作用域注釋
image.png
組件默認(rèn)綁定
image.png
image.png
組默認(rèn)綁定
image.png
組件生命周期
image.png
作用域
image.png
@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();
        
    }}



image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末鲸阻,一起剝皮案震驚了整個(gè)濱河市跋涣,隨后出現(xiàn)的幾起案子缨睡,更是在濱河造成了極大的恐慌,老刑警劉巖陈辱,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件奖年,死亡現(xiàn)場離奇詭異,居然都是意外死亡沛贪,警方通過查閱死者的電腦和手機(jī)拾并,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鹏浅,“玉大人嗅义,你說我怎么就攤上這事∫遥” “怎么了之碗?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長季希。 經(jīng)常有香客問我褪那,道長,這世上最難降的妖魔是什么式塌? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任博敬,我火速辦了婚禮,結(jié)果婚禮上峰尝,老公的妹妹穿的比我還像新娘偏窝。我一直安慰自己,他們只是感情好武学,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布祭往。 她就那樣靜靜地躺著,像睡著了一般火窒。 火紅的嫁衣襯著肌膚如雪硼补。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天熏矿,我揣著相機(jī)與錄音已骇,去河邊找鬼。 笑死票编,一個(gè)胖子當(dāng)著我的面吹牛褪储,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播栏妖,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼乱豆,長吁一口氣:“原來是場噩夢啊……” “哼奖恰!你這毒婦竟也來了吊趾?” 一聲冷哼從身側(cè)響起宛裕,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎论泛,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體屁奏,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡岩榆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了坟瓢。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片勇边。...
    茶點(diǎn)故事閱讀 38,039評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖折联,靈堂內(nèi)的尸體忽然破棺而出粒褒,到底是詐尸還是另有隱情,我是刑警寧澤诚镰,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布奕坟,位于F島的核電站,受9級特大地震影響清笨,放射性物質(zhì)發(fā)生泄漏月杉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一抠艾、第九天 我趴在偏房一處隱蔽的房頂上張望苛萎。 院中可真熱鬧,春花似錦检号、人聲如沸首懈。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽究履。三九已至,卻和暖如春脸狸,著一層夾襖步出監(jiān)牢的瞬間最仑,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工炊甲, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留泥彤,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓卿啡,卻偏偏與公主長得像吟吝,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子颈娜,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容