簡體   English   中英

Android 創建viewModel的不同方式 object 什么時候使用哪一種?

[英]Android different ways to create viewModel object which one to use when?

我最近開始使用 ViewModel 和 AndroidViewModel,我看到初始化 viewModel 實例有不同的方法,對我來說一切正常,我只想知道什么時候使用哪個? 我應該在哪里初始化viewModel object? 以下都是獲取 viewModel 實例並為我工作的不同方法:

    val myViewModel1 = ViewModelProvider(this, ViewModelProvider.NewInstanceFactory()).get(MyViewModel::class.java)
    val myViewModel2 = ViewModelProvider.AndroidViewModelFactory(this.application).create(MyViewModel::class.java)
    val myViewModel3 = ViewModelProvider(this).get(MyViewModel::class.java)
    val myViewModel4: MyViewModel by viewModels()
    val myViewModel5 by viewModels<MyViewModel>()

對我來說最簡單和最簡單的是第 3、第 4 和第 5 種方法,但是我不知道所有五種方法有什么區別,也請告訴我是否有任何其他方法或最佳方法來初始化我的 viewModel object,我在聲明全局變量時對其進行初始化,是否可以在聲明時進行初始化,或者應該在某個生命周期方法中完成?

3是獲取(並在必要時創建)沒有構造函數參數的 ViewModel 的標准方法。 在內部,這是1傳遞一個調用空構造函數( NewInstanceFactory() )的工廠。

AndroidViewModelViewModel的子類,它會自動傳入application引用,以防您需要訪問應用程序上下文等內容。 所以即使你的 AndroidViewModel 沒有參數,創建它的工廠也需要傳入一個application ,這就是2正在做的事情。

默認情況下,這一切都使用3為您處理 - 如果您的 VM 需要配置一些額外的參數,您只需要定義和使用工廠。


45是一回事,只是在不同的地方指定了類型(你只需要一個聲明,另一個將被推斷)。 它們是來自 KTX 庫的代表,它們與3執行相同的操作,但它們在 IMO 中更具可讀性 - 特別是如果您正在混合范圍,例如使用by viewModels來獲取 Fragment 自己的 VM,也可以by activityViewModels讓活動的虛擬機與該片段和其他片段共享數據。

它們也是lazy委托(據我所知),這意味着 VM 僅在首次訪問時才被實例化。 這通常會在生命周期的后期發生(而不是在 object 首次構建時)。 我不確定在構造時初始化 VM是否有問題,但我見過的所有官方示例似乎都在onCreate (或附近)中獲取它

如果有人在尋找深入的答案,請檢查這個,這里我們有以下方法來創建或獲取 viewModel object:

  1. val myViewModel1 = ViewModelProvider(this, ViewModelProvider.NewInstanceFactory()).get(MyViewModel::class.java)

  2. myViewModel2 = ViewModelProvider.AndroidViewModelFactory(this.application).create(MyViewModel::class.java)

  3. val myViewModel3 = ViewModelProvider(this).get(MyViewModel::class.java)

  4. val myViewModel4: MyViewModel by viewModels()

  5. val myViewModel5 by viewModels<MyViewModel>()

所有人都做同樣的事情,唯一的兩個關鍵區別是:

  1. 使用延遲加載和沒有延遲加載的 viewModel 初始化。
  2. 多參數無參數的viewModel。

讓我們看看lazy loading and without lazy loading ,前三個沒有委托by這意味着 object 沒有延遲加載,因此開發人員有責任僅在創建活動或片段時創建視圖模型 object附加到活動,這意味着前三種方法(1、2、3)不能在全局 scope 中使用,如果在全局 scope 中使用,則該變量必須是帶有lateint或 Z37A6259CC0C1DAE29BD19A78668 初始化的 var , 2, 3) 必須發生在 onCreate 或 onViewCreated 中(在片段的情況下)。

因此,創建 viewModel object 的最佳方法是使用 (4, 5) 的by ,兩者相同,但語法略有不同,我選擇 4 是因為它簡單易讀。

val myViewModel4: MyViewModel by viewModels()

by委托提供了延遲加載實例的靈活性,您可以在全局 scope 定義 viewModel 並擺脫樣板代碼,如果您嘗試在沒有委托的情況下在全局 scope 初始化 viewModel,則應用程序將崩潰,因為 viewModel 將嘗試在創建活動之前進行初始化(它不會延遲加載 viewModel 實例)。

現在讓我們看看如何使用多個參數進行延遲加載,問題中沒有提到6th方法。

如果您的視圖 model 中有多個參數並且不使用任何依賴注入,則可以使用 ViewModelFactory 實現,然后延遲加載它:

val myViewModelWithParm: MyViewModel by viewModels { MyViewModelFactory(application, "param1", "param2") }

ViewModelFactory 實現:

    class MyViewModelFactory(val application: Application, val param1: String, val param2: String) :
    ViewModelProvider.Factory {
    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        return MyViewModel(application, param1, param2) as T
    }
}

到目前為止,我們已經清楚了委托初始化 (4, 5),以及它與 (1, 2, 3) 的不同之處現在讓我們看看前 3 種方法 (1, 2, 3) 的區別。

讓我們首先檢查 1 和 2。

  1. val myViewModel1 = ViewModelProvider(this, ViewModelProvider.NewInstanceFactory()).get(MyViewModel::class.java)
  2. myViewModel2 = ViewModelProvider.AndroidViewModelFactory(this.application).create(MyViewModel::class.java)

它們之間的主要區別是一個使用ViewModelProvider.NewInstanceFactory而另一個使用ViewModelProvider.AndroidViewModelFactory ,所以我檢查了這兩個類的源代碼,發現ViewModelProvider.AndroidViewModelFactory實際上是ViewModelProvider.NewInstanceFactory的實現,它覆蓋了create function 這意味着兩者正在做同樣的事情,如果我們想要多個參數,最好選擇這兩種方法但是我們必須重寫ViewModelProvider.NewInstanceFactory來創建我們自己的工廠,就像在這里完成的那樣

現在是第三個:

val myViewModel3 = ViewModelProvider(this).get(MyViewModel::class.java)

當我們的 ViewModel 中沒有多個參數並且不想延遲加載 object 時,這是 1 和 2 的簡單形式。

注意:我強烈推薦方法 4 或 5(兩者語法不同),因為這是最適合和最佳編寫的方法,如果您沒有多個 arguments,如果您有多個 arguments,您可以使用該方法6 通過實現ViewModelProvider.Factory在答案中提到。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM