Android开发经验谈

Jetpack使用(四)ViewModel核心原理

2020-04-03  本文已影响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的内部已经帮我们把旋转需要保存的数据已经保存了。

上一篇下一篇

猜你喜欢

热点阅读