美文网首页Jetpack组件集
Jetpack组件之ViewModel实现原理

Jetpack组件之ViewModel实现原理

作者: Guxxxd | 来源:发表于2021-12-09 15:35 被阅读0次
    提纲
    1. ViewModel是什么
    2. ViewModel的优势
    3. ViewModel基本用法
    4. ViewModel相关方法说明及实现原理

    一、ViewModel是什么

    ViewModel 具备宿主生命周期感知能力的数据存储组件,使用ViewModel保存的数据,在页面因配置变更导致页面销毁重建之后依然也是存在的。

    配置变更:横竖屏切换、分辨率调整、权限变更、系统字体样式变更等

    二、ViewModel的优势

    2.1 页面配置更改数据不丢失

    当设备因配置更改导致 Activity/Fragment 重建,ViewModel 中的数据并不会因此而丢失;
    配合 LiveData 可以在页面重建后立马能收到最新保存的数据用以重新渲染页面。

    2.2 生命周期感应

    当在 ViewModel 中做一些网络请求或数据的处理时,可以复写 onCleared() 方法,终止清理一些操作,释放内存。该方法在宿主 onDestroy 时被调用。

    2.2 数据共享

    • Activity + Fragment 的页面,可以使用 ViewModel 实现页面之间的数据共享;
    • 不同的 Activity也可以实现数据共享。

    三、ViewModel基本用法

    data class MyData(var name:String,var age:Int,var sex:Int)
    
    class MyModel : ViewModel(){
        private val liveData = MutableLiveData<List<MyData>>()
    
        fun loadData(): LiveData<List<MyData>> {
            if (liveData.value == null){
                val list = fromRemote()
                liveData.postValue(list)
            }
            return liveData
        }
    
        fun fromRemote() = listOf(MyData("1",1,1),MyData("2",2,2))
    }
    
    class MainActivity2 : AppCompatActivity() {
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main2)
    
            val viewModel = ViewModelProvider(this).get(MyModel::class.java)
            viewModel.loadData().observe(this, Observer {
                // TODO: do something
            })
        }
    }
    

    四、ViewModel相关方法说明及实现原理

    4.1 相关方法说明

    4.1.1 ViewModelProvider(@NonNull ViewModelStoreOwner owner) 构造方法
       public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
            this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
                    ? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
                    : NewInstanceFactory.getInstance());
        } 
        
        // 赋值mFactory和mViewModelStore
        public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
            mFactory = factory;
            mViewModelStore = store;
        }
    
    4.1.2 T get(@NonNull String key, @NonNull Class<T> modelClass) 获取ViewModel实例
        @NonNull
        @MainThread
        public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
            String canonicalName = modelClass.getCanonicalName();
            if (canonicalName == null) {
                throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
            }
            return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
        } 
    
        @NonNull
        @MainThread
        public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
            // 通过key在ViewModelStore中取Value(ViewModel)
            // ViewModelStore是真正存储ViewModel的地方,其内部维护了一个HashMap<String,ViewModel>
            ViewModel viewModel = mViewModelStore.get(key);
            // viewModel是否存在
            if (modelClass.isInstance(viewModel)) {
                if (mFactory instanceof OnRequeryFactory) {
                    ((OnRequeryFactory) mFactory).onRequery(viewModel);
                }
                // 存在 返回
                return (T) viewModel;
            } else {
                //noinspection StatementWithEmptyBody
                if (viewModel != null) {
                    // TODO: log a warning.
                }
            }
            // 不存在 创建viewModel实例
            if (mFactory instanceof KeyedFactory) {
                viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
            } else {
                viewModel = (mFactory).create(modelClass);
            }
            // 添加到Map中
            mViewModelStore.put(key, viewModel);
            // 返回
            return (T) viewModel;
        }
    

    4.2 实现原理

    ViewModel 可以实现因配置变更导致页面销毁重建之后依然可以复用。准确点来说,应该是页面恢复重建前后获取到的是同一个 ViewModel 实例对象
    ViewModelProvider本质是从传递进去的 ViewModelStore来获取实例。如果没有传递,则利用 factory 去创建一个新的,并存储到 ViewModelStore

    4.2.1 ViewModelStoreOwner在Activity中的实现
       public class ComponentActivity extends androidx.core.app.ComponentActivity implements ViewModelStoreOwner,... {
    
        static final class NonConfigurationInstances {
            Object custom;
            ViewModelStore viewModelStore;
        }
    
        // Lazily recreated from NonConfigurationInstances by getViewModelStore()
        private ViewModelStore mViewModelStore;
    
        /**
         * 应为配置变更导致的act重建时回调的方法
         * getLastNonConfigurationInstance() 方法,是在窗口重建后获取重建前保存的数据
         */
        @Override
        @Nullable
        public final Object onRetainNonConfigurationInstance() {
            Object custom = onRetainCustomNonConfigurationInstance();
            ViewModelStore viewModelStore = mViewModelStore;
            if (viewModelStore == null) {
                // No one called getViewModelStore(), so see if there was an existing
                // ViewModelStore from our last NonConfigurationInstance
                NonConfigurationInstances nc =
                        (NonConfigurationInstances) getLastNonConfigurationInstance();
                if (nc != null) {
                    viewModelStore = nc.viewModelStore;
                }
            }
    
            if (viewModelStore == null && custom == null) {
                return null;
            }
            // 将viewModelStore包装成NonConfigurationInstances对象中保存
            NonConfigurationInstances nci = new NonConfigurationInstances();
            nci.custom = custom;
            nci.viewModelStore = viewModelStore;
            return nci;
        }
    
        @NonNull
        @Override
        public ViewModelStore getViewModelStore() {
            if (getApplication() == null) {
                throw new IllegalStateException("Your activity is not yet attached to the "
                        + "Application instance. You can't request ViewModel before onCreate call.");
            }
            // mViewModelStore为null,可能窗口已经被重建
            if (mViewModelStore == null) {
                // 获取重建前保存的NonConfigurationInstances对象,从而获取mViewModelStore,并赋值当前mViewModelStore
                NonConfigurationInstances nc =
                        (NonConfigurationInstances) getLastNonConfigurationInstance();
                if (nc != null) {
                    // Restore the ViewModelStore from NonConfigurationInstances
                    mViewModelStore = nc.viewModelStore;
                }
                // 如果还为null,说明窗口是第一次被创建
                if (mViewModelStore == null) {
                    // 直接new一个对象
                    mViewModelStore = new ViewModelStore();
                }
            }
            // 返回ViewModelStore
            return mViewModelStore;
        }
    } 
    

    4.2.2 ViewModelStoreOwner在Fragment中的实现

    # Fragment
    public class Fragment implements ViewModelStoreOwner {
        // Internal unique name for this fragment;
        @NonNull
        String mWho = UUID.randomUUID().toString();
    
        // The fragment manager we are associated with.  Set as soon as the
        // fragment is used in a transaction; cleared after it has been removed
        // from all transactions.
        FragmentManagerImpl mFragmentManager;
    
        // Host this fragment is attached to.
        FragmentHostCallback mHost;
    
        @NonNull
        @Override
        public ViewModelStore getViewModelStore() {
            if (mFragmentManager == null) {
                throw new IllegalStateException("Can't access ViewModels from detached fragment");
            }
            return mFragmentManager.getViewModelStore(this);
        }
    }
    
    # FragmentManagerImpl
    /**
     * Container for fragments associated with an activity.
     */
    final class FragmentManagerImpl extends FragmentManager implements LayoutInflater.Factory2 {
        FragmentHostCallback mHost;
        private FragmentManagerViewModel mNonConfig;
    
        @NonNull
        ViewModelStore getViewModelStore(@NonNull Fragment f) {
            return mNonConfig.getViewModelStore(f);
        }
    
        @NonNull
        FragmentManagerViewModel getChildNonConfig(@NonNull Fragment f) {
            return mNonConfig.getChildNonConfig(f);
        }
    }
    
    # FragmentManagerViewModel
    /**
     * FragmentManagerViewModel is the always up to date view of the Fragment's
     * non configuration state
     */
    class FragmentManagerViewModel extends ViewModel {
    
        private static final ViewModelProvider.Factory FACTORY = new ViewModelProvider.Factory() {
            @NonNull
            @Override
            @SuppressWarnings("unchecked")
            public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
                FragmentManagerViewModel viewModel = new FragmentManagerViewModel(true);
                return (T) viewModel;
            }
        };
    
        @NonNull
        static FragmentManagerViewModel getInstance(ViewModelStore viewModelStore) {
            ViewModelProvider viewModelProvider = new ViewModelProvider(viewModelStore,
                    FACTORY);
            return viewModelProvider.get(FragmentManagerViewModel.class);
        }
        
        @NonNull
        ViewModelStore getViewModelStore(@NonNull Fragment f) {
            ViewModelStore viewModelStore = mViewModelStores.get(f.mWho);
            if (viewModelStore == null) {
                viewModelStore = new ViewModelStore();
                mViewModelStores.put(f.mWho, viewModelStore);
            }
            return viewModelStore;
        }
    }
    
    

    相关文章

      网友评论

        本文标题:Jetpack组件之ViewModel实现原理

        本文链接:https://www.haomeiwen.com/subject/ezgsdltx.html