您好,登錄后才能下訂單哦!
這篇“Android ViewModel創建不受橫豎屏切換影響怎么實現”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“Android ViewModel創建不受橫豎屏切換影響怎么實現”文章吧。
在我們項目中, 引入了viewModel 做MVI 設計模式的組成部分,它是JetPack 組件庫中的重要成員。今天來了解下它。
// 在 Activity 中使用 class MainActivity : AppCompatActivity() { // 使用 Activity 的作用域 private val viewModel : MainViewModel by viewModels() } // 在 Fragment 中使用 class MainFragment : Fragment() { // 使用 Activity 的作用域,與 MainActivity 使用同一個對象 val activityViewModel : MainViewModel by activityViewModels() // 使用 Fragment 的作用域 val viewModel : MainViewModel by viewModels() }
// ViewModel 創建工廠 private final Factory mFactory; // ViewModel 存儲容器 private final ViewModelStore mViewModelStore; // 默認使用 NewInstanceFactory 反射創建 ViewModel public ViewModelProvider(ViewModelStoreOwner owner) { this(owner.getViewModelStore(), ... NewInstanceFactory.getInstance()); } // 自定義 ViewModel 創建工廠 public ViewModelProvider(ViewModelStoreOwner owner, Factory factory) { this(owner.getViewModelStore(), factory); } // 記錄宿主的 ViewModelStore 和 ViewModel 工廠 public ViewModelProvider(ViewModelStore store, Factory factory) { mFactory = factory; mViewModelStore = store; } @NonNull @MainThread public <T extends ViewModel> T get(Class<T> modelClass) { String canonicalName = modelClass.getCanonicalName(); if (canonicalName == null) { throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels"); } // 使用類名作為緩存的 KEY return get(DEFAULT_KEY + ":" + canonicalName, modelClass); } // Fragment @NonNull @MainThread public <T extends ViewModel> T get(String key, Class<T> modelClass) { // 1. 先從 ViewModelStore 中取緩存 ViewModel viewModel = mViewModelStore.get(key); if (modelClass.isInstance(viewModel)) { return (T) viewModel; } // 2. 使用 ViewModel 工廠創建實例 viewModel = mFactory.create(modelClass); ... // 3. 存儲到 ViewModelStore mViewModelStore.put(key, viewModel); return (T) viewModel; } // 默認的 ViewModel 工廠 public static class NewInstanceFactory implements Factory { private static NewInstanceFactory sInstance; @NonNull static NewInstanceFactory getInstance() { if (sInstance == null) { sInstance = new NewInstanceFactory(); } return sInstance; } @NonNull @Override public <T extends ViewModel> T create(Class<T> modelClass) { // 反射創建 ViewModel 對象 return modelClass.newInstance(); } }
可以看到:
ViewModel 實例的方法最終是通過 ViewModelProvider 完成的。ViewModelProvider 可以理解為創建 ViewModel 的工具類,它需要 2 個參數:
它對應于 Activity / Fragment 等持有 ViewModel 的宿主,它們內部通過 ViewModelStore 維持一個 ViewModel 的映射表,ViewModelStore 是實現 ViewModel 作用域和數據恢復的關鍵;
它對應于 ViewModel 的創建工廠,缺省時將使用默認的 NewInstanceFactory 工廠來反射創建 ViewModel 實例。
創建 ViewModelProvider 工具類后,你將通過 get() 方法來創建 ViewModel 的實例。get() 方法內部首先會通過 ViewModel 的全限定類名從映射表(ViewModelStore)中取緩存,未命中才會通過 ViewModel 工廠創建實例再緩存到映射表中。 正因為同一個 ViewModel 宿主使用的是同一個 ViewModelStore 映射表,因此在同一個宿主上重復調用 ViewModelProvider.get() 返回同一個 ViewModel 實例。
// ViewModel 本質上就是一個映射表而已 public class ViewModelStore { // <String - ViewModel> 哈希表 private final HashMap<String, ViewModel> mMap = new HashMap<>(); final void put(String key, ViewModel viewModel) { ViewModel oldViewModel = mMap.put(key, viewModel); if (oldViewModel != null) { oldViewModel.onCleared(); } } final ViewModel get(String key) { return mMap.get(key); } Set<String> keys() { return new HashSet<>(mMap.keySet()); } public final void clear() { for (ViewModel vm : mMap.values()) { vm.clear(); } mMap.clear(); } }
ViewModel 宿主是 ViewModelStoreOwner 接口的實現類,例如 ComponentActivity:
public class ComponentActivity extends androidx.core.app.ComponentActivity implements ContextAware, LifecycleOwner, ViewModelStoreOwner ... { // ViewModel 的存儲容器 private ViewModelStore mViewModelStore; // ViewModel 的創建工廠 private ViewModelProvider.Factory mDefaultFactory; @NonNull @Override public ViewModelStore getViewModelStore() { if (mViewModelStore == null) { // 已簡化過程 mViewModelStore = new ViewModelStore(); } return mViewModelStore; } }
由此,ViewModel 的創建其實跟activity 是相關聯的。
可以看到,在 ComponentActivity
構造方法中添加了生命周期的判斷,當 Activity onDestroy 時,如果是發生了橫豎屏切換,就不會走 getViewModelStore().clear()
,清理操作,保證了ViewModel 持有的數據還能存在。
通過getLastNonConfigurationInstance()
獲取 NonConfigurationInstances
實例,從而得到這個實例中的 viewModelStore
而且,Activity 生命周期的變化都會走這個方法,來保證viewModelStore
不為空。
在 Activity 屏幕旋轉時,onRetainNonConfigurationInstance()
在onStop
和onDestroy
之間調用
onRetainNonConfigurationInstance()
是個重要的方法
這保證了 在銷毀前,viewModelStore
實例被拿到并交給 NonConfigurationInstances
實例,將 viewModelStore
賦值給他
以上就是關于“Android ViewModel創建不受橫豎屏切換影響怎么實現”這篇文章的內容,相信大家都有了一定的了解,希望小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。