当前位置:网站首页>一文带你了解 ViewModel 的使用及源码解析

一文带你了解 ViewModel 的使用及源码解析

2022-08-10 22:54:00 Android技术栈

前言

学习ViewModel之前首先我们得简单了解下MVP和MVVM,因为ViewModel是MVVM中的一个元素

MVPMVVM

在MVP中View想要调用Model数据层,需要经过中间层Presenter, 这样就实现了View和Model的解耦,这也是MVP和MVC的差别; 但是如果一个Activity中有太多交互,那么我们的View接口数量就会很庞大达到十几个也不足为奇,并且在View层调用了Presenter之后,会反过来调用View层,这样显得繁琐

而MVVM的出现就解决了这个问题; 说到MVVM的话,我们放上Google的架构图

MVVM中的VM指的就是ViewModel; 从上图为没看到,因为ViewModel中持有了LiveData,而LiveData是一个可观察的数据类型;在View层中,将被观察的数据LiveData订阅,并提供了一个观察者Observer,当数据发生变化的时候,就会回调Observer中的onChanged()方法,从而更新UI, 这个过程是系统源码帮我们处理的,所以就没有上面Presenter中调用View的那一步了

ViewModel概述

应用的某个 Activity 中可能包含用户列表; 因配置更改而重新创建 Activity 后,新 Activity 必须重新提取用户列表

对于简单的数据,Activity 可以使用onSaveInstanceState() 方法从 onCreate() 中的捆绑包恢复其数据; 但此方法仅适合可以序列化再反序列化的少量数据,而不适合数量可能较大的数据,如用户列表或位图,使用ViewModel可以解决这个问题

另外,界面控制器经常需要进行异步调用,这些调用可能需要一些时间才能返回结果; 界面控制器需要管理这些调用,并确保系统在其销毁后清理这些调用以避免潜在的内存泄露;此项管理需要大量的维护工作,并且在因配置更改而重新创建对象的情况下,会造成资源的浪费,因为对象可能需要重新发出已经发出过的调用,使用ViewModel可以解决这个问题

诸如 Activity 和 Fragment 之类的界面控制器主要用于显示界面数据、对用户操作做出响应或处理操作系统通信(如权限请求); 如果要求界面控制器也负责从数据库或网络加载数据,那么会使类越发膨胀。为界面控制器分配过多的责任可能会导致单个类尝试自己处理应用的所有工作,而不是将工作委托给其他类;以这种方式为界面控制器分配过多的责任也会大大增加测试的难度

ViewModel 类旨在以注重生命周期的方式存储和管理界面相关的数据;ViewModel 类让数据可在发生屏幕旋转等配置更改后继续存在

ViewModel使用

ViewModel的使用比较简单,我们想要使用使用的话直接继承ViewModel或者继承AndroidViewModel即可; AndroidViewModel源码如下,他们俩的区别,是AndroidViewModel中多了一个Application的成员变量以及以Application为参数的构造方法,如果你需要Application的话,就直接继承AndroidViewModel即可

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n15" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">public class AndroidViewModel extends ViewModel {
 @SuppressLint("StaticFieldLeak")
 private Application mApplication;

 public AndroidViewModel(@NonNull Application application) {
 mApplication = application;
 }

 /**
 * Return the application.
 */
 @SuppressWarnings({"TypeParameterUnusedInFormals", "unchecked"})
 @NonNull
 public <T extends Application> T getApplication() {
 return (T) mApplication;
 }
}
</pre>

这里以我写的一个Demo为例,我们自定义一个AppsViewModel如下:

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n17" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">class AppsViewModel(appsRepository: AppsRepository) : ViewModel() {
 val apps: LiveData<List<AppEntity>> = appsRepository.loadApps()
}
</pre>

因为我们这里传入了一个参数,所以需要定义一个Factory,代码如下:

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n19" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> class AppsViewModelFactory(private val repository: AppsRepository) : ViewModelProvider.Factory {
 override fun <T : ViewModel?> create(modelClass: Class<T>): T {
 return AppsViewModel(repository) as T
 }
}
</pre>

接下来就是使用了:

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n21" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">class AppsListFragment : Fragment() {

 private lateinit var viewModel: AppsViewModel

 //-----1-----
 private val viewModel: AppsViewModel by viewModels {
 FactoryProvider.providerAppsFactory(requireContext())
 }

 override fun onActivityCreated(savedInstanceState: Bundle?) {
 //-----2-----
 viewModel = ViewModelProviders.of(this,FactoryProvider.providerAppsFactory(requireContext()))
 .get(AppsViewModel::class.java)
 //-----3-----
 viewModel.apps.observe(viewLifecycleOwner, Observer {
 //Update UI
 })
 }
}
</pre>

我们先声明了一个变量viewModel,我们可以通过注释1处的 by viewModels提供一个自定义的Factory; 但是需要添加一个依赖:implementation "androidx.fragment:fragment-ktx:1.2.2;或者采用注释2的方式直接使用ViewModelProviders.of(fragment,factory).get(class)的形式获取实例

然后就直接使用了,在注释3处使用viewmodel.apps.observe将其加入生命周期观察中,如果数据发生变化就会调用Observer的回调,从而更新UI

ViewModel源码

  • 上面我们采用ViewModelProviders.of(...).get(class)方法获取ViewModel,我们就从这里开始源码开始分析,我们先看下这个类的源码:
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n28" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">@Deprecated
public class ViewModelProviders {
 @Deprecated
 public ViewModelProviders() {
 }

 @Deprecated
 @NonNull
 @MainThread
 public static ViewModelProvider of(@NonNull Fragment fragment) {
 return new ViewModelProvider(fragment);
 }

 @Deprecated
 @NonNull
 @MainThread
 public static ViewModelProvider of(@NonNull FragmentActivity activity) {
 return new ViewModelProvider(activity);
 }

 @Deprecated
 @NonNull
 @MainThread
 public static ViewModelProvider of(@NonNull Fragment fragment, @Nullable Factory factory) {
 if (factory == null) {
 factory = fragment.getDefaultViewModelProviderFactory();
 }
 return new ViewModelProvider(fragment.getViewModelStore(), factory);
 }


 @Deprecated
 @NonNull
 @MainThread
 public static ViewModelProvider of(@NonNull FragmentActivity activity,
 @Nullable Factory factory) {
 if (factory == null) {
 factory = activity.getDefaultViewModelProviderFactory();
 }
 return new ViewModelProvider(activity.getViewModelStore(), factory);
 }


 @SuppressWarnings("WeakerAccess")
 @Deprecated
 public static class DefaultFactory extends ViewModelProvider.AndroidViewModelFactory {

 @Deprecated
 public DefaultFactory(@NonNull Application application) {
 super(application);
 }
 }
}
</pre>

我们看到此类中提供了四个方法,其实着四个都以一样,我们以第四个为例分析; 第一个参数是Activity,第二个参数是一个Factory,默认情况下我们是不需要传入Factory这个参数的; 如果不传入的话,我们跟进构造方法就能看到默认是用NewInstanceFactory来作为Factory的,看到内部的create方法通过反射生成了一个ViewModel,实例源码如下:

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n30" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">public static class NewInstanceFactory implements Factory {

 private static NewInstanceFactory sInstance;

 /**
 * Retrieve a singleton instance of NewInstanceFactory.
 *
 * @return A valid {@link NewInstanceFactory}
 */
 @NonNull
 static NewInstanceFactory getInstance() {
 if (sInstance == null) {
 sInstance = new NewInstanceFactory();
 }
 return sInstance;
 }

 @SuppressWarnings("ClassNewInstance")
 @NonNull
 @Override
 public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
 //noinspection TryWithIdenticalCatches
 try {
 return modelClass.newInstance();
 } catch (InstantiationException e) {
 throw new RuntimeException("Cannot create an instance of " + modelClass, e);
 } catch (IllegalAccessException e) {
 throw new RuntimeException("Cannot create an instance of " + modelClass, e);
 }
 }
}
</pre>
  • 如果传入Factory参数的话,就会用我们自定义的Factory作来生成ViewModel

  • of方法调用结束返回的是ViewModelProvider, 然后调用的是get方法,我们看下这个类的部分源码:

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n36" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">public class ViewModelProvider {

 private static final String DEFAULT_KEY ="androidx.lifecycle.ViewModelProvider.DefaultKey";

 private final Factory mFactory;
 private final ViewModelStore mViewModelStore;

 //-----1-----
 public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
 this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
 ? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
 : NewInstanceFactory.getInstance());
 }

 public ViewModelProvider(@NonNull ViewModelStoreOwner owner, @NonNull Factory factory) {
 this(owner.getViewModelStore(), factory);
 }

 public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
 mFactory = factory;
 mViewModelStore = store;
 }

 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);
 }

 public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
 ViewModel viewModel = mViewModelStore.get(key);

 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.
 }
 }
 if (mFactory instanceof KeyedFactory) {
 viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
 } else {
 viewModel = (mFactory).create(modelClass);
 }
 mViewModelStore.put(key, viewModel);
 return (T) viewModel;
 }
}
</pre>

上面截取的部分源码其实是ViewModelProvider最重要的方法了; 我们先看此类中有两个重要的成员变量,其中一个是mFactory, 注释1处看到如果我们没有传入factory的话,默认实现的是NewInstanceFactory, 印证了我们之前的说法

还有一个是ViewModelStore, 它是怎么来的呢? 因为ComponentActivity中实现了接口ViewModelStoreOwner,在ViewModelProvider的构造方法中调用owner.getViewModelStore(),这个owner就是ComponentActivity自身,然后获取到了ViewModelStore这个变量,实际调用的源码如下:

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n38" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">@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.");
 }
 //-----1-----
 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;
}
</pre>

在注释1处,判断如果mViewModelStore == null的话,就会调取getLastNonConfigurationInstance尝试获取; 如果获取到了就将获取到的赋值给mViewModelStore返回。这里就涉及到一个重要的知识点了,为什么说ViewModel在横竖屏切换的时候能够持久的保存数据,不需要像之前一样调用onSaveInstanceState? 因为在Activity被销毁的时候,还会调用另外一个方法onRetainNonConfigurationInstance, 我们看它在ComponentActivity中的源码实现:

<pre spellcheck="false" class="md-fences mock-cm md-end-block" lang="java" cid="n40" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">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;
    }
	//----1-----
    NonConfigurationInstances nci = new NonConfigurationInstances();
    nci.custom = custom;
    nci.viewModelStore = viewModelStore;
    return nci;
}
</pre>

我们看到在注释1的地方将我们之前存在的viewModelStore存储到NonConfigurationInstances中了,然后在调用getViewModelStore的时候调用getLastNonConfigurationInstance这样就保证了Activity销毁之前和之后的viewModelStore是同一个,那它里面存储的ViewModel值也就是同样的了。所以ViewModel的生命周期可以用下图来概括:

接下来我们分析get方法:

<pre spellcheck="false" class="md-fences mock-cm md-end-block" lang="java" cid="n44" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">private static final String DEFAULT_KEY =
        "androidx.lifecycle.ViewModelProvider.DefaultKey"

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);
}
</pre>
  • 首先获取类的全称的字符串名字,和DEFAULT_KEY拼凑成一个Key,然后调用get的重载方法如下:
<pre spellcheck="false" class="md-fences mock-cm md-end-block" lang="java" cid="n48" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
    ViewModel viewModel = mViewModelStore.get(key);
	//-----1-----
    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.
        }
    }
    if (mFactory instanceof KeyedFactory) {
        viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
    } else {
    	//-----2-----
        viewModel = (mFactory).create(modelClass);
    }
    mViewModelStore.put(key, viewModel);
    return (T) viewModel;
}
</pre>

注释1处判断我们的modelClass是不是属于ViewModel类型的,并且判断mFactory的类型是否属于OnRequeryFactory类型,如果是的话,就返回值;

在注释2处使用Factory通过反射创建一个viewModel, 然后将其存入mViewModelStore中;我们看下ViewModelStore的源码:

<pre spellcheck="false" class="md-fences mock-cm md-end-block" lang="java" cid="n50" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">public class ViewModelStore {

    private final HashMap<String, ViewModel> mMap = new HashMap<>();

    final void put(String key, ViewModel viewModel) {
        ViewModel oldViewModel = mMap.put(key, viewModel);
        if (oldViewModel != null) {
            oldViewModel.onCleared();
        }
    }

    final ViewModel get(String key) {
        return mMap.get(key);
    }

    Set<String> keys() {
        return new HashSet<>(mMap.keySet());
    }

    /**
     *  Clears internal storage and notifies ViewModels that they are no longer used.
     */
    public final void clear() {
        for (ViewModel vm : mMap.values()) {
            vm.clear();
        }
        mMap.clear();
    }
}
</pre>

ViewModelStore的源码很简单,内部持有了一个HashMap对象,用来存放ViewModel。ViewModel的创建到此就结束了。然后就是使用的问题, 使用如下

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n52" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">override fun onActivityCreated(savedInstanceState: Bundle?) {
 viewModel = ViewModelProviders.of(this,FactoryProvider.providerAppsFactory(requireContext()))
 .get(AppsViewModel::class.java)
 viewModel.apps.observe(viewLifecycleOwner, Observer {
 //Update UI
 }) 
}
</pre>

ViewModel的使用涉及到LiveData和Lifecycle部分,这里就不再多说了

好了,文章基本上就到这里,如有地方不对或者有不同理解的可以提出来

有需要文中完整代码的同学可以在评论区下方留言 “底层源码” 或者直接私信我即可 免费获取

最后我想说:

对于程序员来说,要学习的知识内容、技术有太多太多,要想不被环境淘汰就只有不断提升自己,从来都是我们去适应环境,而不是环境来适应我们

技术是无止境的,你需要对自己提交的每一行代码、使用的每一个工具负责,不断挖掘其底层原理,才能使自己的技术升华到更高的层面

Android 架构师之路还很漫长,与君共勉

原网站

版权声明
本文为[Android技术栈]所创,转载请带上原文链接,感谢
https://blog.csdn.net/m0_70748845/article/details/125730730