您好,登录后才能下订单哦!
本文小编为大家详细介绍“Android Jetpack库之ViewModel组件怎么使用”,内容详细,步骤清晰,细节处理妥当,希望这篇“Android Jetpack库之ViewModel组件怎么使用”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。
ViewModel是一个可感知Activity或Fragment生命周期的一个架构组件,当视图销毁,数据也会被清除,所以它的本质就是用来存储与视图相关的数据,让视图显示控制与数据分离,即使界面配置发生改变数据也不会被销毁,通常配合LiveData使用
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val binding = ActivityMainBinding.inflate(LayoutInflater.from(baseContext)) setContentView(binding.root) //获取ViewModel实例 val viewModel: TextViewModel = ViewModelProvider(this).get(TextViewModel::class.java) //订阅数据 viewModel.liveData.observe(this, { println(it) }) //调用函数 viewModel.test() } class TextViewModel : ViewModel() { val liveData = MediatorLiveData<String>() fun test() { liveData.postValue("Hello") } } }
1,使用ViewModelProvider获取ViewModel实例
2,订阅VIewModel的LiveData
3,调用ViewModel的方法
public ViewModelProvider(@NonNull ViewModelStoreOwner owner) { this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory ? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory() : NewInstanceFactory.getInstance()); } public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) { mFactory = factory; mViewModelStore = store;
1,当我们创建ViewModelProvider的时候需要传入一个ViewModelStoreOwner对象,ViewModelStoreOwner是负责提供ViewModelStore对象的, 而ComponentActivity实现了这个接口,所以我们默认传当前的Activity即可
2,首先判断是否有默认的ViewModel工厂,如果没有就创建一个Factory
3,Factory是用来创建ViewModel的,ViewModelStore是用来存储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中取 ViewModel viewModel = mViewModelStore.get(key); //如果取到ViewModel 代表已经创建过这个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. } } //通过Factor利用反射创建一个实例 if (mFactory instanceof KeyedFactory) { viewModel = ((KeyedFactory) mFactory).create(key, modelClass); } else { viewModel = mFactory.create(modelClass); } //把ViewModel实例存储到ViewModelStore中 mViewModelStore.put(key, viewModel); return (T) viewModel; }
1,当我们调用get()方法时会先获取类名,然后生成一个唯一的key
2,先通过key到ViewModelStore中取ViewModel,如果不为空代表已经创建过这个ViewModel的实例,直接返回这个实例
3,如果为空就通过工厂利用java反射机制创建一个实例,通过键值对形式保存到ViewModelStore中,返回实例,看到这里是不是对为什么多个fragment可以共享同一个ViewModel的疑问豁然开朗了,因为Fragment是依附于Activity之上的,在我们构建ViewModelProvider的时候传入同一个Activity,那么ViewModelProvider得到的ViewModelStore是同一个,在我们调用get()方法时就能通过key到ViewModelStore中取到同一个ViewModel实例,说白了就是共用Activity的ViewModel
ActivityThread{ private void handleRelaunchActivityInner(ActivityClientRecord r, int configChanges, List<ResultInfo> pendingResults, List<ReferrerIntent> pendingIntents, PendingTransactionActions pendingActions, boolean startsNotResumed, Configuration overrideConfig, String reason) { // Preserve last used intent, it may be set from Activity#setIntent(). final Intent customIntent = r.activity.mIntent; // Need to ensure state is saved. if (!r.paused) { performPauseActivity(r, false, reason, null /* pendingActions */); } if (!r.stopped) { callActivityOnStop(r, true /* saveState */, reason); } //销毁Activity handleDestroyActivity(r.token, false, configChanges, true, reason); //启动Activity handleLaunchActivity(r, pendingActions, customIntent); } }
1,当我们切换横竖屏的时候,ActivityThread会接收到RELAUNCH_ACTIVITY消息,会调用自身的handleRelaunchActivityInner(),这个方法里面有一个参数r,类型是ActivityClientRecord,我们每打开一个Activity,ActivityThread就会生成这么个对象来记录我们打开的Activity并保存起来
2,handleRelaunchActivityInner()这个方法里调用了handleDestroyActivity()方法去销毁我们的Activity
ActivityThread{ @Override public void handleDestroyActivity(IBinder token, boolean finishing, int configChanges, boolean getNonConfigInstance, String reason) { //执行销毁Activity ActivityClientRecord r = performDestroyActivity(token, finishing, configChanges, getNonConfigInstance, reason); } ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing, int configChanges, boolean getNonConfigInstance, String reason) { //通过token获取Activity的记录 ActivityClientRecord r = mActivities.get(token); if (r != null) { //是否需要获取配置实例 if (getNonConfigInstance) { try { //调用Activity的retainNonConfigurationInstances方法获取配置实例 r.lastNonConfigurationInstances = r.activity.retainNonConfigurationInstances(); } catch (Exception e) { } } r.setState(ON_DESTROY); } //通过token移除这条Activity的记录 synchronized (mResourcesManager) { mActivities.remove(token); } return r; } }
3,handleDestroyActivity()则直接调用了performDestroyActivity()方法去销毁Activity,核心部分就是调用了Activity的retainNonConfigurationInstances()方法获取了配置实例并复制给了ActivityClientRecord,把NonConfigurationInstances实例保存起来
Activity{ NonConfigurationInstances retainNonConfigurationInstances() { //获取NonConfigurationInstances对象 Object activity = onRetainNonConfigurationInstance(); HashMap<String, Object> children = onRetainNonConfigurationChildInstances(); FragmentManagerNonConfig fragments = mFragments.retainNestedNonConfig(); mFragments.doLoaderStart(); mFragments.doLoaderStop(true); ArrayMap<String, LoaderManager> loaders = mFragments.retainLoaderNonConfig(); //创建NonConfigurationInstances实例 NonConfigurationInstances nci = new NonConfigurationInstances(); nci.activity = activity; nci.children = children; nci.fragments = fragments; nci.loaders = loaders; if (mVoiceInteractor != null) { mVoiceInteractor.retainInstance(); nci.voiceInteractor = mVoiceInteractor; } return nci; } } ComponentActivity{ @Override @Nullable public final Object onRetainNonConfigurationInstance() { Object custom = onRetainCustomNonConfigurationInstance(); //获取ViewModelStore 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实例 NonConfigurationInstances nci = new NonConfigurationInstances(); nci.custom = custom; nci.viewModelStore = viewModelStore; return nci; } }
4, 通过查阅源码,一层一层的往下剖析,ActivityThread是通过这样的调用链来获取我们的ViewModelStore实例并保存在ActivityClientRecord中的
ActivityThread{ private void handleRelaunchActivityInner(ActivityClientRecord r, int configChanges, List<ResultInfo> pendingResults, List<ReferrerIntent> pendingIntents, PendingTransactionActions pendingActions, boolean startsNotResumed, Configuration overrideConfig, String reason) { // Preserve last used intent, it may be set from Activity#setIntent(). final Intent customIntent = r.activity.mIntent; // Need to ensure state is saved. if (!r.paused) { performPauseActivity(r, false, reason, null /* pendingActions */); } if (!r.stopped) { callActivityOnStop(r, true /* saveState */, reason); } //销毁Activity handleDestroyActivity(r.token, false, configChanges, true, reason); //启动Activity handleLaunchActivity(r, pendingActions, customIntent); } }
1,当handleDestroyActivity执行完毕就已经把ViewModelStore的实例获取到并存放到ActivityClientRecord中,此时就开始执行handleLaunchActivity()方法来启动activity
2,handleLaunchActivity()这个方法也需要ActivityClientRecord这个参数,而此时ActivityClientRecord这个对象正是经过handleDestroyActivity()这个方法获取并保存了ViewModelStore 实例的对象
3,handleLaunchActivity()则调用了performLaunchActivity()方法来启动Activity
ActivityThread{ @Override public Activity handleLaunchActivity(ActivityClientRecord r, PendingTransactionActions pendingActions, Intent customIntent) { // Make sure we are running with the most recent config. handleConfigurationChanged(null, null); //去启动Activity final Activity a = performLaunchActivity(r, customIntent); return a; } private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { try { Application app = r.packageInfo.makeApplication(false, mInstrumentation); if (activity != null) { CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager()); Configuration config = new Configuration(mCompatConfiguration); if (r.overrideConfig != null) { config.updateFrom(r.overrideConfig); } if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity " + r.activityInfo.name + " with config " + config); Window window = null; if (r.mPendingRemoveWindow != null && r.mPreserveWindow) { window = r.mPendingRemoveWindow; r.mPendingRemoveWindow = null; r.mPendingRemoveWindowManager = null; } appContext.setOuterContext(activity); //调用当前打开的Activity的attach()方法 activity.attach(appContext, this, getInstrumentation(), r.token, r.ident, app, r.intent, r.activityInfo, title, r.parent, r.embeddedID, r.lastNonConfigurationInstances, config, r.referrer, r.voiceInteractor, window, r.configCallback, r.assistToken); r.activity = activity; } r.setState(ON_CREATE); //保存这条Activity记录 synchronized (mResourcesManager) { mActivities.put(r.token, r); } } catch (SuperNotCalledException e) { throw e; } catch (Exception e) { } return activity; } }
4,通过代码发现performLaunchActivity调用了当前正在打开的Activity的attach方法,而这个方法需要一个NonConfigurationInstances类型的参数,这个参数里面就有我们的ViewModelStore实例
Activity{ final void attach(Context context, ActivityThread aThread, Instrumentation instr, IBinder token, int ident, Application application, Intent intent, ActivityInfo info, CharSequence title, Activity parent, String id, NonConfigurationInstances lastNonConfigurationInstances, Configuration config, String referrer, IVoiceInteractor voiceInteractor, Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken) { attachBaseContext(context); mFragments.attachHost(null /*parent*/); //赋值给mLastNonConfigurationInstances mLastNonConfigurationInstances = lastNonConfigurationInstances; setAutofillOptions(application.getAutofillOptions()); setContentCaptureOptions(application.getContentCaptureOptions()); } public Object getLastNonConfigurationInstance() { return mLastNonConfigurationInstances != null ? mLastNonConfigurationInstances.activity : null; } } ComponentActivity{ 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) { //先去lastNonConfigurationInstance中取,没有再创建 NonConfigurationInstances nc = (NonConfigurationInstances) getLastNonConfigurationInstance(); if (nc != null) { // Restore the ViewModelStore from NonConfigurationInstances mViewModelStore = nc.viewModelStore; } if (mViewModelStore == null) { mViewModelStore = new ViewModelStore(); } } return mViewModelStore; } }
5,在attach方法里就把这个参数赋值给mLastNonConfigurationInstances,当我们获取ViewModelStore实例的时候,就会先去mLastNonConfigurationInstances中取,如果没有再自己创建一个ViewModelStore实例,到这里整个调用链就搞明白了
ComponentActivity{ public ComponentActivity(){ //订阅生命周期,当生命周期==ON_DESTROY,清除ViewModel数据 getLifecycle().addObserver(new LifecycleEventObserver() { @Override public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) { if (event == Lifecycle.Event.ON_DESTROY) { if (!isChangingConfigurations()) { getViewModelStore().clear(); } } } }); } } ViewModelStore{ public final void clear() { //遍历所有ViewModel并调用其clear()方法清空数据 for (ViewModel vm : mMap.values()) { vm.clear(); } //清空所有ViewModel mMap.clear(); } }
读到这里,这篇“Android Jetpack库之ViewModel组件怎么使用”文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注亿速云行业资讯频道。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。