当前位置:   article > 正文

ViewModel 使用及原理解析,kotlin函数式编程_kotlin viewmodel

kotlin viewmodel

/**

  • 用于构建一个ViewModelProvider,当Activity是alive时它会保留所有的该Activity对应的ViewModels.

*/

@MainThread

public static ViewModelProvider of(@NonNull FragmentActivity activity) {

return of(activity, null);

}

@MainThread

public static ViewModelProvider of(@NonNull FragmentActivity activity,

@Nullable Factory factory) {

//检查application是否为空,不为空则接收

Application application = checkApplication(activity);

if (factory == null) {

//构建一个ViewModelProvider.AndroidViewModelFactory

factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);

}

return new ViewModelProvider(activity.getViewModelStore(), factory);

}

ViewModelProviders里面的of()函数其实是为了方便我们构建一个ViewModelProvider.而ViewModelProvider,一看名字就知道干啥的了,就是提供ViewModel的.

Factory是ViewModelProvider的一个内部接口,它的实现类是拿来构建ViewModel实例的.它里面只有一个方法,就是创建一个ViewModel.

/**

  • Implementations of {@code Factory} interface are responsible to instantiate ViewModels.

*/

public interface Factory {

/**

  • Creates a new instance of the given {@code Class}.

  • @param modelClass a {@code Class} whose instance is requested

  • @param The type parameter for the ViewModel.

  • @return a newly created ViewModel

*/

@NonNull

T create(@NonNull Class modelClass);

}

Factory有2个实现类:一个是NewInstanceFactory, 一个是AndroidViewModelFactory .

  • NewInstanceFactory源码

public static class NewInstanceFactory implements Factory {

@SuppressWarnings(“ClassNewInstance”)

@NonNull

@Override

public T create(@NonNull Class 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);

}

}

}

NewInstanceFactory专门用来实例化那种构造方法里面没有参数的class,并且ViewModel里面是不带Context的,然后它是通过newInstance()去实例化的.

  • AndroidViewModelFactory 源码

public static class AndroidViewModelFactory extends ViewModelProvider.NewInstanceFactory {

private static AndroidViewModelFactory sInstance;

/**

  • Retrieve a singleton instance of AndroidViewModelFactory.

  • @param application an application to pass in {@link AndroidViewModel}

  • @return A valid {@link AndroidViewModelFactory}

*/

@NonNull

public static AndroidViewModelFactory getInstance(@NonNull Application application) {

if (sInstance == null) {

sInstance = new AndroidViewModelFactory(application);

}

return sInstance;

}

private Application mApplication;

/**

  • Creates a {@code AndroidViewModelFactory}

  • @param application an application to pass in {@link AndroidViewModel}

*/

public AndroidViewModelFactory(@NonNull Application application) {

mApplication = application;

}

@NonNull

@Override

public T create(@NonNull Class modelClass) {

if (AndroidViewModel.class.isAssignableFrom(modelClass)) {

//noinspection TryWithIdenticalCatches

try {

return modelClass.getConstructor(Application.class).newInstance(mApplication);

} catch (NoSuchMethodException e) {

throw new RuntimeException("Cannot create an instance of " + modelClass, e);

} catch (IllegalAccessException e) {

throw new RuntimeException("Cannot create an instance of " + modelClass, e);

} catch (InstantiationException e) {

throw new RuntimeException("Cannot create an instance of " + modelClass, e);

} catch (InvocationTargetException e) {

throw new RuntimeException("Cannot create an instance of " + modelClass, e);

}

}

return super.create(modelClass);

}

}

AndroidViewModelFactory专门用来实例化那种构造方法里面有参数的class,并且ViewModel里面可能是带Context的.

  • 它是通过newInstance(application)去实例化的.如果有带application参数则是这样实例化

  • 如果没有带application参数的话,则还是会走newInstance()方法去构建实例.

AndroidViewModelFactory通过构造方法给ViewModel带入Application,就可以在ViewModel里面拿到Context,因为Application是APP全局的,那么不存在内存泄露的问题.完美解决了有些ViewModel里面需要Context引用,但是又担心内存泄露的问题.

下面我们继续ViewModelProviders.of(this)方法继续分析吧,注意最后一句new ViewModelProvider(activity.getViewModelStore(), factory);第一个参数会调用activity的getViewModelStore()方法(这个方法会返回ViewModelStore,这个类是拿来存储ViewModel的,下面会说到),这里的activity是androidx.fragment.app.FragmentActivity,看一下这个getViewModelStore()方法

/**

  • 获取这个Activity相关联的ViewModelStore

*/

@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;

}

//没想到吧,Activity在横竖屏切换时悄悄保存了viewModelStore

//注意,这是FragmentActivity中的NonConfigurationInstances(其实Activity中还定义了一个NonConfigurationInstances,内容要比这个多一些,但是由于没有关系到它,这里就不提及了)

static final class NonConfigurationInstances {

Object custom;

ViewModelStore viewModelStore;

FragmentManagerNonConfig fragments;

}

Android横竖屏切换时会触发onSaveInstanceState(),而还原时会调用onRestoreInstanceState(),但是Android的Activity类还有2个方法名为onRetainNonConfigurationInstance()和getLastNonConfigurationInstance()这两个方法。

来具体看看这2个素未谋面的方法

/**

保留所有fragment的状态。你不能自己覆写它!如果要保留自己的状态,请使用onRetainCustomNonConfigurationInstance()

这个方法在FragmentActivity里面

*/

@Override

public final Object onRetainNonConfigurationInstance() {

Object custom = onRetainCustomNonConfigurationInstance();

FragmentManagerNonConfig fragments = mFragments.retainNestedNonConfig();

if (fragments == null && mViewModelStore == null && custom == null) {

return null;

}

NonConfigurationInstances nci = new NonConfigurationInstances();

nci.custom = custom;

nci.viewModelStore = mViewModelStore;

nci.fragments = fragments;

return nci;

}

//这个方法在Activity里面,而mLastNonConfigurationInstances.activity实际就是就是上面方法中年的nci

public Object getLastNonConfigurationInstance() {

return mLastNonConfigurationInstances != null

? mLastNonConfigurationInstances.activity : null;

}

我们来看看getLastNonConfigurationInstance()的调用时机,

protected void onCreate(@Nullable Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

NonConfigurationInstances nc =

(NonConfigurationInstances) getLastNonConfigurationInstance();

if (nc != null && nc.viewModelStore != null && mViewModelStore == null) {

mViewModelStore = nc.viewModelStore;

}

}

没想到吧,Activity在横竖屏切换时悄悄保存了viewModelStore,放到了NonConfigurationInstances实例里面,横竖屏切换时保存了又恢复了回来,相当于ViewModel实例就还在啊,也就避免了横竖屏切换时的数据丢失.

2. viewModelProvider.get(UserModel.class)

下面我们来到那句构建ViewModel代码的后半段,它是ViewModelProvider的get()方法,看看实现,其实很简单

public T get(@NonNull Class 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 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.

}

}

//无缓存 则重新通过mFactory构建

viewModel = mFactory.create(modelClass);

//缓存起来

mViewModelStore.put(key, viewModel);

//noinspection unchecked

return (T) viewModel;

}

大体思路是利用一个key来缓存ViewModel,有缓存则用缓存的,没有则重新构建.构建时使用的factory是上面of()方法的那个factory.

3. ViewModelStore

上面多个地方用到了ViewModelStore,它其实就是一个普普通通的保存ViewModel的类.

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

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
img

Android开发除了flutter还有什么是必须掌握的吗?

相信大多数从事Android开发的朋友们越来越发现,找工作越来越难了,面试的要求越来越高了

除了基础扎实的java知识,数据结构算法,设计模式还要求会底层源码,NDK技术,性能调优,还有会些小程序和跨平台,比如说flutter,以思维脑图的方式展示在下图;

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img
基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!**

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
[外链图片转存中…(img-yDfnKega-1712677841050)]

Android开发除了flutter还有什么是必须掌握的吗?

相信大多数从事Android开发的朋友们越来越发现,找工作越来越难了,面试的要求越来越高了

除了基础扎实的java知识,数据结构算法,设计模式还要求会底层源码,NDK技术,性能调优,还有会些小程序和跨平台,比如说flutter,以思维脑图的方式展示在下图;

[外链图片转存中…(img-XG0l7E6c-1712677841050)]

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-H8ChrkPE-1712677841051)]

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/752240
推荐阅读
相关标签
  

闽ICP备14008679号