Jetpack使用(四)ViewModel核心原理

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

使用

public class MyViewModel extends ViewModel {
        private MutableLiveData> users;
        public LiveData> getUsers() {
            if (users == null) {
                users = new MutableLiveData>();
                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 children;
        FragmentManagerNonConfig fragments;
        ArrayMap loaders;
        VoiceInteractor voiceInteractor;
    }

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

    @NonNull
    @MainThread
    public  T get(@NonNull String key, @NonNull Class 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的内部已经帮我们把旋转需要保存的数据已经保存了。

阅读全文
下载说明:
1、本站所有资源均从互联网上收集整理而来,仅供学习交流之用,因此不包含技术服务请大家谅解!
2、本站不提供任何实质性的付费和支付资源,所有需要积分下载的资源均为网站运营赞助费用或者线下劳务费用!
3、本站所有资源仅用于学习及研究使用,您必须在下载后的24小时内删除所下载资源,切勿用于商业用途,否则由此引发的法律纠纷及连带责任本站和发布者概不承担!
4、本站站内提供的所有可下载资源,本站保证未做任何负面改动(不包含修复bug和完善功能等正面优化或二次开发),但本站不保证资源的准确性、安全性和完整性,用户下载后自行斟酌,我们以交流学习为目的,并不是所有的源码都100%无错或无bug!如有链接无法下载、失效或广告,请联系客服处理!
5、本站资源除标明原创外均来自网络整理,版权归原作者或本站特约原创作者所有,如侵犯到您的合法权益,请立即告知本站,本站将及时予与删除并致以最深的歉意!
6、如果您也有好的资源或教程,您可以投稿发布,成功分享后有站币奖励和额外收入!
7、如果您喜欢该资源,请支持官方正版资源,以得到更好的正版服务!
8、请您认真阅读上述内容,注册本站用户或下载本站资源即您同意上述内容!
原文链接:https://www.dandroid.cn/archives/19468,转载请注明出处。
0

评论0

显示验证码
没有账号?注册  忘记密码?