美文网首页Android开发经验谈
Jetpack使用(四)ViewModel核心原理

Jetpack使用(四)ViewModel核心原理

作者: 程序员三千_ | 来源:发表于2020-04-03 15:12 被阅读0次

    Jetpack使用(一)Lifecycles核心原理
    Jetpack使用(二)LiveData核心原理
    Jetpack使用(三)DataBinding核心原理
    Jetpack使用(四)ViewModel核心原理
    Jetpack使用(五)Navigation核心原理

    ViewModel其实是和前面说的LiveData一起组合使用的,引用官方的一句话:ViewModel类旨在以注重生命周期的方式存储和管理界面相关的数据。ViewModel类让数据可在发生屏幕旋转等配置更改后继续存在。也就是如果使用了ViewModel,那么在屏幕旋转的时候,我们不用再使用 onSaveInstanceState() 方法从 onCreate() 中的恢复数据,其实已经在onRetainNonConfigurationInstance里帮我们做了保存机制。

    使用

    public class MyViewModel extends ViewModel {
            private MutableLiveData<List<User>> users;
            public LiveData<List<User>> getUsers() {
                if (users == null) {
                    users = new MutableLiveData<List<User>>();
                    loadUsers();
                }
                return users;
            }
    
            private void loadUsers() {
                // Do an asynchronous operation to fetch users.
            }
        }
        
    
     public class MyActivity extends AppCompatActivity {
            public void onCreate(Bundle savedInstanceState) {
                // Create a ViewModel the first time the system calls an activity's onCreate() method.
                // Re-created activities receive the same MyViewModel instance created by the first activity.
    
                MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class);
                model.getUsers().observe(this, users -> {
                    // update UI
                });
            }
        }
    

    看过前面三篇文章的话,应该对于observe这些观察者代码很了解,所以我们只源码分析MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class);这一句代码,来看看到底是怎么实现屏幕旋转保存数据的。

    核心原理

    我们先进入ViewModelProviders.of(this)。of方法看看

     @NonNull
        @MainThread
        public static ViewModelProvider of(@NonNull FragmentActivity activity,
                @Nullable Factory factory) {
            Application application = checkApplication(activity);
            if (factory == null) {
                factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
            }
            return new ViewModelProvider(activity.getViewModelStore(), factory);
        }
    
    

    这段代码的意思就是通过getInstance方法返回一个AndroidViewModelFactory传进去,返回一个ViewModelProvider,所以我们看看activity.getViewModelStore()到底是怎么实现的

        @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.");
            }
            if (mViewModelStore == null) {
                NonConfigurationInstances nc =
                        (NonConfigurationInstances) getLastNonConfigurationInstance();
                if (nc != null) {
                    // Restore the ViewModelStore from NonConfigurationInstances
                    mViewModelStore = nc.viewModelStore;
                }
                if (mViewModelStore == null) {
                    mViewModelStore = new ViewModelStore();
                }
            }
            return mViewModelStore;
        }
    

    mViewModelStore是一个ViewModelStore类型的变量,是ComponentActivity的成员变量,如果mViewModelStore为null,就先新建一个NonConfigurationInstances对象nc,我们看看getLastNonConfigurationInstance到底是什么

     public Object getLastNonConfigurationInstance() {
            return mLastNonConfigurationInstances != null
                    ? mLastNonConfigurationInstances.activity : null;
        }
    
       static final class NonConfigurationInstances {
            Object activity;
            HashMap<String, Object> children;
            FragmentManagerNonConfig fragments;
            ArrayMap<String, LoaderManager> loaders;
            VoiceInteractor voiceInteractor;
        }
    

    从上面代码可以看出,nc里就是保存了actvity或者fragment的一些屏幕旋转时的数据信息的,所以如果mViewModelStore等于空,他会把新建一个mViewModelStore,并把actvity或者fragment的信息存储进去了,of分析完了,我们再回到前面,看看get(StudentViewModel.class);是怎么实现的

        @NonNull
        @MainThread
        public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
            ViewModel viewModel = mViewModelStore.get(key);
    
            if (modelClass.isInstance(viewModel)) {
                //noinspection unchecked
                return (T) viewModel;
            } else {
                //noinspection StatementWithEmptyBody
                if (viewModel != null) {
                    // TODO: log a warning.
                }
            }
            if (mFactory instanceof KeyedFactory) {
                viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
            } else {
                viewModel = (mFactory).create(modelClass);
            }
            mViewModelStore.put(key, viewModel);
            //noinspection unchecked
            return (T) viewModel;
        }
    

    一直点进去最后到这里,发现最终是通过create方法生成viewModel的,create方法一直进去就是通过反射生成viewModel的,最后把生成的viewModel放进
    mViewModelStore里。
    最后再看到ComponentActivity里屏幕旋转时要调用到的方法

      @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;
            }
    
            NonConfigurationInstances nci = new NonConfigurationInstances();
            nci.custom = custom;
            nci.viewModelStore = viewModelStore;
            return nci;
        }
    

    综上源码分析,所以我们可以得出结论;MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class);这段代码的意思是:通过反射创建了一个MyViewModel,并把MyViewModel和当前activty的状态一起保存到mViewModelStore里,mViewModelStore是每个actvity的ViewModelStore类型的成员变量,所以mViewModelStore的内部已经帮我们把旋转需要保存的数据已经保存了。

    相关文章

      网友评论

        本文标题:Jetpack使用(四)ViewModel核心原理

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