溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

怎么在Android和Hilt中限定作用域

發(fā)布時間:2021-10-28 17:34:01 來源:億速云 閱讀:188 作者:iii 欄目:移動開發(fā)

這篇文章主要介紹“怎么在Android和Hilt中限定作用域”,在日常操作中,相信很多人在怎么在Android和Hilt中限定作用域問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”怎么在Android和Hilt中限定作用域”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!

將對象 A 的作用域限定到對象 B,指的是對象 B 的整個生命周期內(nèi)始終持有相同的 A 實例。當涉及到 DI (依賴項注入) 時,限定對象 A  的作用域為一個容器,則意味著該容器在銷毀之前始終提供相同的 A 實例。

怎么在Android和Hilt中限定作用域

在 Hilt 中,您可以通過注解將類型的作用域限定在某些容器或組件內(nèi)。例如,您的應(yīng)用中有一個處理登錄和注銷的 UserManager  類型。您可以使用@Singleton 注解將該類型的作用域限定為ApplicationComponent (ApplicationComponent  是一個被整個應(yīng)用的生命周期管理的容器)。被限定作用域的類型在應(yīng)用組件中沿組件層次結(jié)構(gòu)向下傳遞: 在本案例中,相同的 UserManager  實例將被提供給層次結(jié)構(gòu)內(nèi)其余的 Hilt 組件。應(yīng)用中任何依賴于 UserManager 的類型都將獲得相同的實例。

  • 組件層次結(jié)構(gòu)https://developer.android.google.cn/training/dependency-injection/hilt-android#component-hierarchy

注意: 默認情況下,Hilt  中的綁定都未限定作用域。這些綁定不屬于任何組件,并且可以在整個項目中被訪問。每次被請求都會提供該類型的不同實例。當您將綁定的作用域限定為某個組件時,它會限制您使用該綁定的范圍以及該類型可以具有的依賴項。

在 Android 中,您不使用 DI 庫也可以通過 Android Framework 來手動限定作用域。讓我們看看如何手動限定作用域,以及如何改用  Hilt 來限定作用域。最后,我們將比較使用 Android Framework 手動限定作用域和使用 Hilt 限定作用域的區(qū)別。

在 Android 中限定作用域

看了上文的定義,您可能會有這樣的異議: 在某個特定類中使用一個類型的實例變量也可以做到限定該變量類型的作用域。沒錯!不使用 DI  時,您可以執(zhí)行如下操作:

class ExampleActivity : AppCompatActivity() {   private val analyticsAdapter = AnalyticsAdapter()   ... }

analyticsAdapter 變量的作用域被限定為 MyActivity 的生命周期,這意味著只要 Activity  沒有被銷毀,該變量就是同一個實例。如果另一個類出于某種原因需要訪問這個被限定了作用域的變量,每次訪問也會獲得相同實例。當新的MyActivity 實例被創(chuàng)建時  (如系統(tǒng)設(shè)置改變),一個新的 AnalyticsAdapter 實例將會被創(chuàng)建。

使用 Hilt,等效代碼如下:

@ActivityScoped class AnalyticsAdapter @Inject constructor() { ... }  @AndroidEntryPoint class ExampleActivity : AppCompatActivity() {   @Inject lateinit var analyticsAdapter: AnalyticsAdapter  }

每次創(chuàng)建的 MyActivity 都會持有一個 ActivityComponent DI 容器的新實例,在 Activity  被銷毀之前,該實例將向組件層次結(jié)構(gòu)下的依賴項提供相同的AnalyticsAdapter 實例。

  • 組件層次結(jié)構(gòu)https://developer.android.google.cn/training/dependency-injection/hilt-android#component-hierarchy

怎么在Android和Hilt中限定作用域
更改系統(tǒng)設(shè)置后,您將獲得一個新的 AnalyticsAdapter 和 MainActivity 實例

通過 ViewModel 限定作用域

然而,我們可能希望 AnalyticsAdapter 可以在系統(tǒng)設(shè)置更改后留存!或者說,我們希望直到用戶離開 Activity  之前,都限定該實例的作用域為 Activity。

為此,您可以使用組件架構(gòu)中的 ViewModel,因為它可以在系統(tǒng)設(shè)置更改后留存。

  • 組件架構(gòu)中的  ViewModelhttps://developer.android.google.cn/topic/libraries/architecture/viewmodel

不使用依賴項注入時,您可能有如下代碼:

class AnalyticsAdapter() { ... }  class ExampleViewModel() : ViewModel() {   val analyticsAdapter = AnalyticsAdapter() }  class ExampleActivity : AppCompatActivity() {    private val viewModel: ExampleViewModel by viewModels()   private val analyticsAdapter = viewModel.analyticsAdapter  }

通過這種方式,您將 AnalyticsAdapter 的作用域限定為 ViewModel。因為 Activity 具有 ViewModel  的訪問權(quán)限,所以在該 Activity 中可以始終獲得相同的 AnalyticsAdapter 實例。

通過使用 Hilt,您可以通過限定 AnalyticsAdapter 的作用域為ActivityRetainedComponent  來實現(xiàn)相同的行為,因為ActivityRetainedComponent 也可以在系統(tǒng)設(shè)置更改后留存。

@ActivityRetainedScoped class AnalyticsAdapter @Inject constructor() { ... }  @AndroidEntryPoint class ExampleActivity : AppCompatActivity() {  @Inject lateinit var analyticsAdapter: AnalyticsAdapter  }

怎么在Android和Hilt中限定作用域

通過使用 ViewModel 或者 Hilt 中的 ActivityRetainedScope 注解,您可以在系統(tǒng)設(shè)置更改后獲得相同的實例

如果您希望在遵循良好的 DI 實踐的同時,保留 ViewModel 用于處理視圖邏輯,您可以使用 @ViewModelInject 提供  ViewModel 的依賴項,該注解的詳細描述請參見: 文檔 | 使用 Hilt 注入 ViewModel 對象。這樣一來,AnalyticsAdapter  的作用域就無需被限定為ActivityRetainedComponent,因為此時它的作用域被手動限定為 ViewModel:

  • 文檔 | 使用 Hilt 注入 ViewModel  對象https://developer.android.google.cn/training/dependency-injection/hilt-jetpack#viewmodels

class AnalyticsAdapter @Inject constructor() { ... }  class ExampleViewModel @ViewModelInject constructor(   private val analyticsAdapter: AnalyticsAdapter ) : ViewModel() { ... }  @AndroidEntryPoint class ExampleActivity : AppCompatActivity() {    private val viewModel: ExampleViewModel by viewModels()   private val analyticsAdapter = viewModel.analyticsAdapter  }

我們剛才所看到的內(nèi)容,可以應(yīng)用到任何由 Android Framework 生命周期類管理的 Hilt  組件中。點擊查看全部可用作用域?;氐轿覀冏畛醯氖纠?,將作用域限定為 ApplicationComponent,等同于不使用 DI 框架時在  Application 類中持有該實例。

  • 全部可用作用域https://developer.android.google.cn/training/dependency-injection/hilt-android#component-scopes

對比 Hilt 及 ViewModel 限定作用域

使用 Hilt 限定作用域,優(yōu)勢為您可在 Hilt 組件層次結(jié)構(gòu)中使用被限定的類型;而對于 ViewModel,則必須通過 ViewModel  手動訪問被限定作用域的類型。

使用 ViewModel 限定作用域,優(yōu)勢為您可以在應(yīng)用中任何 LifecyclerOwner對象中持有 ViewModel。例如,如果您使用了  Jetpack Navigation 庫,則可以將 ViewModel 綁定到 NavGraph 上。

  • LifecyclerOwner  https://developer.android.google.cn/reference/androidx/lifecycle/LifecycleOwner

  • Jetpack Navigation  庫https://developer.android.google.cn/guide/navigation/navigation-getting-started

  • NavGraphhttps://developer.android.google.cn/reference/androidx/navigation/fragment/NavHostFragment

Hilt 提供的作用域數(shù)量有限??赡軟]有符合您特定使用場景的作用域。例如嵌套 Fragment,對于這種情況,您可以退一步使用 ViewModel  限定作用域。

使用 Hilt 注入 ViewModel

如上文所述,您可以使用 @ViewModelInject 向 ViewModel 注入依賴項。其原理是這些綁定關(guān)系保存在  ActivityRetainedComponent  中,這也是為什么您只能注入未限定作用域的類型,或者是限定作用域為ActivityRetainedComponent 以及  ApplicationComponent 的類型。

如果 Activity 或 Fragment 被 @AndroidEntryPoint  注解修飾,就可以通過getDefaultViewModelProviderFactory() 方法獲取 Hilt 生成的 ViewModel 工廠了。由于可以在  ViewModelProvider 中使用這些 ViewModel 工廠,使您獲取 ViewModel 的方式變得更加靈活。例如:  將作用域限定為BackStackEntry 的 ViewModel。

限定作用域會有一些代價,因為提供的對象在持有者被銷毀之前將一直保留在內(nèi)存中。請在應(yīng)用中慎重地考慮使用限定作用域的對象。如果對象的內(nèi)部狀態(tài)要求使用同一實例,對象需要同步,或者對象的創(chuàng)建成本很高,那么限定作用域是恰當?shù)淖龇ā?/p>

當然,當您需要限定作用域時,您可以使用 Hilt 中的作用域注解,也可以直接使用 Android Framework。

到此,關(guān)于“怎么在Android和Hilt中限定作用域”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI