Android Jetpack组件架构:ViewModel的原理

这篇具有很好参考价值的文章主要介绍了Android Jetpack组件架构:ViewModel的原理。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Android Jetpack组件架构:ViewModel的原理

Android Jetpack组件架构:ViewModel的原理,Android开发笔记,android jetpack,架构,android

导言

本篇文章是关于介绍ViewModel的,由于ViewModel的使用还是挺简单的,这里就不再介绍其的基本应用,我们主要来分析ViewModel的原理。

ViewModel的生命周期

众所周知,一般使用ViewModel是用来解决两个问题的,第一个就是关于设备配置发生改变时Activity先前状态的保存,在ViewModel出来之前我们一般会使用saveInstanceState这个Bundle来进行状态的保存,但是这样做能存储的数据是有限的,结构也不够明确,ViewModel作为一个生命周期大于Activity的组件就可以帮我们实现状态的存储,下面是ViewModel生命周期与Activity对比的图:
Android Jetpack组件架构:ViewModel的原理,Android开发笔记,android jetpack,架构,android
可以看到直到Activity被完全Destory时ViewModel中的数据才会被清除。

我们使用ViewModel的第二个原因就是用来实现MVVM架构,可以通过DataBinding组件和ViewModel组件以及LiveData组件一起实现MVVM架构,这样可以减轻Activity的职责,避免Activity过于臃肿。

获得ViewModel的提供者

我们从ViewModel的创建开始分析其原理,这里用我们上一篇文章的例子:

mViewModel = ViewModelProvider(this).get(SimpViewModel::class.java)

这里首先会通过ViewModelProvider的构造方法获得一个ViewModelProvider的实例,其构造方法如下所示:

public constructor(
    owner: ViewModelStoreOwner
) : this(owner.viewModelStore, defaultFactory(owner), defaultCreationExtras(owner))

constructor(
    private val store: ViewModelStore,
    private val factory: Factory,
    private val defaultCreationExtras: CreationExtras = CreationExtras.Empty,
)

可以看到我们调用的是第一个构造方法,最终会调用到第二个构造方法中,也就是主构造方法中,这个构造来说就是指定了三个成员变量,分别是ViewModelStore,FactoryCreationExtras三个类型的参数,我们先来分别介绍一下这三个类型。

ViewModelStore – ViewModel的拥有者

着整个类比较小,但是也是有注释的,我们先来看看注释:
Android Jetpack组件架构:ViewModel的原理,Android开发笔记,android jetpack,架构,android
这段注释中比较重要的信息就是ViewModel是真正用来存储ViewModel的类并且在configuration changes就是配置发生改变时新的实例和旧的实例中的信息是一致的。只有当持有者不再会被recreated时里面的数据才会通过clear清除。

接下来我们来看该类的源码:

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

    public final void clear() {
        for (ViewModel vm : mMap.values()) {
            vm.clear();
        }
        mMap.clear();
    }
}

可以看到具体是用一个哈希表来存储viewModel的实例的,里面唯一比较大的方法就是put方法,里面做的处理就是将替换出来的旧的viewModel实例给清理掉。

Factory – ViewModel的创建工厂

这个Factory是一个定义在ViewModelProvider的内部接口,它的主要职责是用来初始化ViewModel,说实话就是一个工厂。我们来看其定义:

    public interface Factory {
        public fun <T : ViewModel> create(modelClass: Class<T>): T {
            throw UnsupportedOperationException(
                "Factory.create(String) is unsupported.  This Factory requires " +
                    "`CreationExtras` to be passed into `create` method."
            )
        }

        public fun <T : ViewModel> create(modelClass: Class<T>, extras: CreationExtras): T =
            create(modelClass)

        companion object {
            @JvmStatic
            fun from(vararg initializers: ViewModelInitializer<*>): Factory =
                InitializerViewModelFactory(*initializers)
        }
    }

不过这里是一个抽象的,我们来找一个具体的,也就是defaultFactory方法获取的工厂:

public companion object {
    internal fun defaultFactory(owner: ViewModelStoreOwner): Factory =
        if (owner is HasDefaultViewModelProviderFactory)
            owner.defaultViewModelProviderFactory else instance
     	......       
}

这个方法的逻辑就是判断ViewModel的持有者是不是有默认的工厂方法,如果有的话就获取持有者的默认工厂,否则返回的是自身的instance实例,至于这个instance实例是在NewInstanceFactory这个实现了Factory接口的工厂类中定义的伴生变量,具体逻辑是:

@JvmStatic
public val instance: NewInstanceFactory
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    get() {
        if (sInstance == null) {
            sInstance = NewInstanceFactory()
        }
        return sInstance!!
    }

可以看到instance是一个静态的单例,他具体指向的还是这个NewInstanceFactory类,至于它是如何初始化/创建ViewModel的实例的我们可以看一眼它的create方法:

override fun <T : ViewModel> create(modelClass: Class<T>): T {
    return try {
        modelClass.newInstance()
    } catch (e: InstantiationException) {
        throw RuntimeException("Cannot create an instance of $modelClass", e)
    } catch (e: IllegalAccessException) {
        throw RuntimeException("Cannot create an instance of $modelClass", e)
    }
}

这个传入的modelClass就是我们传入的.class文件:

ViewModelProvider(this).get(SimpViewModel::class.java)

所以可以看到,这个默认情况下的工厂就是直接用反射生成了对应ViewModel的实例。

CreationExtras – 构建ViewModel时的额外参数

首先我们来看一看注释的内容:
Android Jetpack组件架构:ViewModel的原理,Android开发笔记,android jetpack,架构,android
简单来说它就是为工厂生成实例的时候提供额外参数的,这些参数使用一个Map来存储的了,不过默认情况下我们并不需要实现额外的工厂,所以这个类型我们先略过。

获得ViewModel的实例

前面我们已经知道了通过构造ViewModelProvider我们可以获得其Factory了,接下来继续向下看:

ViewModelProvider(this).get(SimpViewModel::class.java)

我们看一看get方法做了什么:

    public open operator fun <T : ViewModel> get(modelClass: Class<T>): T {
        val canonicalName = modelClass.canonicalName
            ?: throw IllegalArgumentException("Local and anonymous classes can not be ViewModels")
        return get("$DEFAULT_KEY:$canonicalName", modelClass)
    }

    public open operator fun <T : ViewModel> get(key: String, modelClass: Class<T>): T {
        val viewModel = store[key]
        if (modelClass.isInstance(viewModel)) {
            (factory as? OnRequeryFactory)?.onRequery(viewModel)
            return viewModel as T
        } else {
            @Suppress("ControlFlowWithEmptyBody")
            if (viewModel != null) {
                // TODO: log a warning.
            }
        }
        val extras = MutableCreationExtras(defaultCreationExtras)
        extras[VIEW_MODEL_KEY] = key
        return try {
            factory.create(modelClass, extras)
        } catch (e: AbstractMethodError) {
            factory.create(modelClass)
        }.also { store.put(key, it) }
    }

可以看到第一个方法会调用第二个方法,其中第一个方法向第二个方法传入的的第一个String类型的参数是通过DEFAULT_KEY和我们传入的类的类名拼接而成的。然后跳转到第二个方法之中去,首先会尝试从ViewModleStroe中获取对应Key对应的ViewModel,但是一般第一次创建时应该会为null,所以之后跳转的应该是最后return块中的factory.create方法之中,这个方法我们在之前Factory的介绍中提到过了,具体就是通过反射实例化ViewModel的,并且最后将其放入到ViewModelStore对象之中去。

至于多次获取同一个ViewModel实例是会跳转到:

 if (modelClass.isInstance(viewModel)) {
            (factory as? OnRequeryFactory)?.onRequery(viewModel)
            return viewModel as T
        } 

这一段中去,这里onRequery默认是无实现的,也就是说并不会对viewModel做任何的处理。

ViewModelStore在哪里被创建

既然ViewModel是被存储在ViewModelStore之中的,那ViewModelStore究竟是在哪里被创建出来的呢?我们可以在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.");
    }
    ensureViewModelStore();
    return mViewModelStore;
}

void ensureViewModelStore() {
    if (mViewModelStore == null) {
        NonConfigurationInstances nc =
                (NonConfigurationInstances) getLastNonConfigurationInstance(); //获得上次配置更改的相关参数
        if (nc != null) { //当存在上次的参数时
            // Restore the ViewModelStore from NonConfigurationInstances
            mViewModelStore = nc.viewModelStore; //恢复上次的参数
        }
        if (mViewModelStore == null) {
            mViewModelStore = new ViewModelStore(); //创建一个新的ViewModelStore
        }
    }
}

可以看到这里在获得ViewModelStore时主要是通过一个NonConfigurationInstances ,而该参数是一个静态的对象,也就是说,它是一个单例,这样就保证了Activity在整个生命周期之中只有一个ViewModelStore实例,从而实现配置改变时也可以恢复数据的作用。

Activity的默认工厂

在看ComponentActivity的源码时,发现了原来Activity也是有默认工厂的,它的具体实现如下:

    constructor(application: Application?, owner: SavedStateRegistryOwner, defaultArgs: Bundle?) {
        savedStateRegistry = owner.savedStateRegistry
        lifecycle = owner.lifecycle
        this.defaultArgs = defaultArgs
        this.application = application
        factory = if (application != null) getInstance(application)
            else ViewModelProvider.AndroidViewModelFactory()
    }

这个方法最终设置到的工厂类都是一个名为AndroidViewModelFactory的工厂类:

    public open class AndroidViewModelFactory
    private constructor(
        private val application: Application?,
        // parameter to avoid clash between constructors with nullable and non-nullable
        // Application
        @Suppress("UNUSED_PARAMETER") unused: Int,
    ) : NewInstanceFactory() {
    
        @Suppress("SingletonConstructor")
        public constructor() : this(null, 0)

        @Suppress("SingletonConstructor")
        public constructor(application: Application) : this(application, 0)

        @Suppress("DocumentExceptions")
        override fun <T : ViewModel> create(modelClass: Class<T>, extras: CreationExtras): T {
            return if (application != null) {
                create(modelClass)
            } else {
                val application = extras[APPLICATION_KEY]
                if (application != null) {
                    create(modelClass, application)
                } else {
                    // For AndroidViewModels, CreationExtras must have an application set
                    if (AndroidViewModel::class.java.isAssignableFrom(modelClass)) {
                        throw IllegalArgumentException(
                            "CreationExtras must have an application by `APPLICATION_KEY`"
                        )
                    }
                    super.create(modelClass)
                }
            }
        }

        @Suppress("DocumentExceptions")
        override fun <T : ViewModel> create(modelClass: Class<T>): T {
            return if (application == null) {
                throw UnsupportedOperationException(
                    "AndroidViewModelFactory constructed " +
                        "with empty constructor works only with " +
                        "create(modelClass: Class<T>, extras: CreationExtras)."
                )
            } else {
                create(modelClass, application)
            }
        }

        @Suppress("DocumentExceptions")
        private fun <T : ViewModel> create(modelClass: Class<T>, app: Application): T {
            return if (AndroidViewModel::class.java.isAssignableFrom(modelClass)) {//如果传入的Class类型实现的接口和AndroidViewModel::class一致,及说明也有生命周期,调用构造犯法并且传入application对象
                try {
                    modelClass.getConstructor(Application::class.java).newInstance(app)
                } catch (e: NoSuchMethodException) {
                    throw RuntimeException("Cannot create an instance of $modelClass", e)
                } catch (e: IllegalAccessException) {
                    throw RuntimeException("Cannot create an instance of $modelClass", e)
                } catch (e: InstantiationException) {
                    throw RuntimeException("Cannot create an instance of $modelClass", e)
                } catch (e: InvocationTargetException) {
                    throw RuntimeException("Cannot create an instance of $modelClass", e)
                }
            } else super.create(modelClass)
        }

        public companion object {
            internal fun defaultFactory(owner: ViewModelStoreOwner): Factory =
                if (owner is HasDefaultViewModelProviderFactory)
                    owner.defaultViewModelProviderFactory else instance

            internal const val DEFAULT_KEY = "androidx.lifecycle.ViewModelProvider.DefaultKey"

            private var sInstance: AndroidViewModelFactory? = null
            
            @JvmStatic
            public fun getInstance(application: Application): AndroidViewModelFactory {
                if (sInstance == null) {
                    sInstance = AndroidViewModelFactory(application)
                }
                return sInstance!!
            }
            
            private object ApplicationKeyImpl : Key<Application>
            
            @JvmField
            val APPLICATION_KEY: Key<Application> = ApplicationKeyImpl
        }
    }

具体通过getInstance方法就跳转到了这里,可以发现似乎工厂类都是一个单例的模式,这个工厂的特殊之处就是他的create方法涉及到了Application对象的传入,比如说这里的newInstance方法:

modelClass.getConstructor(Application::class.java).newInstance(app)

public T newInstance(Object ... initargs)
    throws InstantiationException, IllegalAccessException,
           IllegalArgumentException, InvocationTargetException
{
    if (serializationClass == null) {
        return newInstance0(initargs);
    } else {
        return (T) newInstanceFromSerialization(serializationCtor, serializationClass);
    }
}

也就是说整个被传入Application的生命周期内都只有一个实例,这样由于创建的实例在生命周期范围内的单例性和ViewModelStore的单例性,整个ViewModel就可以实现在整个Activity的生命周期内(发生意外,比如说配置改变时)数据不变更的作用。文章来源地址https://www.toymoban.com/news/detail-729039.html

到了这里,关于Android Jetpack组件架构:ViewModel的原理的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Android JetPack 深入分析ViewModel源码

    本文主要分析 ViewModel 相关源码,相关使用不再赘述,可参考Android ViewModel使用; ViewModel 概览 Google官方给的 ViewModel 定义如下: 定义主要提到两个关键点: 生命周期 上图是Google官网提供的 ViewModel生命周期图示 ,可以看到 ViewModel 的生命周期是从 onCreate 创建到 完成并销毁

    2024年02月11日
    浏览(44)
  • Jetpack业务架构—四件套(Lifecycle、ViewModel、LiveData、DataBinding)

    Jetpack 是一个由多个库组成的套件,可帮助开发者遵循最佳做法、减少样板代码并编写可在各种 Android 版本和设备中一致运行的代码,让开发者可将精力集中于真正重要的编码工作。 Android Jetpack组件的优势: Jetpack推出的主要目的是为了能够让开发者更加快速、方便以及高质

    2024年02月09日
    浏览(41)
  • 如何合理使用 Jetpack 组件开发 Android 项目?

    Jetpack 是 Android 官方推出的一套开发库,其中包含众多的组件,可以让 Android 开发者更快更高效地开发应用程序。Jetpack 组件分为四大部分:架构、行为、UI 和基础组件。 下面详细阐述如何合理使用 Jetpack 组件开发 Android 项目。 在使用 Jetpack 组件之前,首先应熟悉几个常用的

    2024年02月02日
    浏览(42)
  • Android笔记(六):JetPack Compose常见的UI组件

    Text显示的文本来源可以引用res-values-strings.xml中的资源,如第一个显示文本所示。 点击按钮前: 点击按钮后: 点击第一个圆角按钮不放时,显示为按钮:true Button有两方面需要注意: (1) Buttton有一个参数interactionSource,用来监听组件状态的事件源,通过它获取组件的状态来

    2024年02月04日
    浏览(54)
  • Android笔记(七)Android JetPack Compose组件搭建Scaffold脚手架

    在去年2022年曾发布一篇关于脚手架的文章:“Android JetPack Compose组件中Scaffold的应用” 。但是Android的版本从12变更到13及以上版本,导致一些细节的实现存在不同。在本文中,将从头开始介绍整个脚手架的搭建过程。 在Android Studio(版本是Graffie)中新建模块,选择“Empty Activ

    2024年02月04日
    浏览(47)
  • Android Jetpack 从使用到源码深耕【调度任务组件WorkManager 从实践到原理 】(三)

    本文,是Jetpack 调度任务组件WorkManager 从实践到原理系列文章的最后一篇,本文我们将对WorkManager 任务的具体执行源码,进行深入的解读。 大家坐好,我们要开始飙车了。 书接上文,我们既然知道了WorkManager,既然把worker包装为了workrequset,然后提交到了线程池执行,那么我

    2023年04月08日
    浏览(34)
  • Android Jetpack 从使用到源码深耕【调度任务组件WorkManager 从实践到原理 】(一)

    本文,我们对Jetpack的调度任务组件WorkManager ,由使用入手,对其源码进行深入学习、总结一下。 研究这个框架之前,我们基于自己已有的知识体系,想一些问题,给自己设定一些目标,带着目标和问题,去阅读这块的源码,相信收获会更多更深一些。 1) WorkManager 是做什么

    2024年02月02日
    浏览(48)
  • Android Jetpack 从使用到源码深耕【调度任务组件WorkManager 从实践到原理 】(二)

    上文,我们进行了google 任务调度系列知识体系的回顾、探索,引出了WorkManager 。然后我们基于一个简单的需求背景,进行了WorkManager的引入使用,不过从使用上,我们看到和JobScheduler几乎一样的使用步骤,所以猜想内部实现原理,估计和JobScheduler差不多,本文,我们就WorkMa

    2023年04月09日
    浏览(43)
  • 大型Android项目架构:基于组件化+模块化+Kotlin+协程+Flow+Retrofit+Jetpack+MVVM架构实现WanAndroid客户端

    前言:苟有恒,何必三更眠五更起;最无益,莫过一日曝十日寒。 之前一直想写个 WanAndroid 项目来巩固自己对 Kotlin+Jetpack+协程 等知识的学习,但是一直没有时间。这里重新行动起来,从项目搭建到完成前前后后用了两个月时间,平常时间比较少,基本上都是只能利用零碎的

    2024年02月09日
    浏览(54)
  • 沉思篇-剖析Jetpack的ViewModel

    ViewModel做为架构组件的三元老之一,是实现MVVM的有力武器。 ViewModel的基本功能就是管理UI的数据。其实,从职责上来说,这又是对Activity和Fragment的一次功能拆分。以前存储在它们内部的数据,需要它们自己处理创建,更新,存储,恢复的所有过程,同时它们还要处理UI的数据

    2024年02月08日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包