当前位置: 首页 > news >正文

Jetpack ViewModel源码分析

文章目录

  • Jetpack ViewModel源码分析
    • ViewModel生命周期图
    • 源码分析
      • ViewModelStore类
      • ViewModelProvider类
      • ComponentActivity类
      • by viewModels()
      • 数据保存阶段
        • ActivityThread#handleDestroyActivity#
        • ActivityThread#performDestroyActivity
        • Activity#retainNonConfigurationInstances()
        • Activity#onRetainNonConfigurationInstance()
        • androidx.activity.ComponentActivity#onRetainNonConfigurationInstance()
      • 数据恢复阶段
        • ActivityThread#handleRelaunchActivity()
        • ActivityThread#handleRelaunchActivityInner()
        • ActivityThread#handleLaunchActivity
        • ActivityThread#performLaunchActivity()
        • Activity#attach()
        • ComponentActivity#getViewModelStore()

Jetpack ViewModel源码分析

ViewModel生命周期图

在这里插入图片描述

源码分析

ViewModelStore类

//ViewModelStore本质是一个哈希表,键值对形式
public class ViewModelStore {
    
    //key:"androidx.lifecycle.ViewModelProvider.DefaultKey"+ViewModel类名的拼接
    //value:ViewModel对象
    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());
    }

    //清除内部存储并通知viewmodel它们不再使用。
    public final void clear() {
        for (ViewModel vm : mMap.values()) {
            vm.clear();
        }
        mMap.clear();
    }
}

ViewModelProvider类

public open class ViewModelProvider @JvmOverloads constructor(
    private val store: ViewModelStore,
    private val factory: Factory,
    private val defaultCreationExtras: CreationExtras = CreationExtras.Empty,
) {

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

    @MainThread
    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")
        //使用类名拼接作为换成的key
        return get("$DEFAULT_KEY:$canonicalName", modelClass)
    }

    @MainThread
    public open operator fun <T : ViewModel> get(key: String, modelClass: Class<T>): T {
        //ViewModelStore通过key获取ViewModel对象
        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 {
            //使用工厂模式创建ViewModel对象,创建后存储在ViewModelStore中
            factory.create(modelClass, extras)
        } catch (e: AbstractMethodError) {
            factory.create(modelClass)
        }.also { store.put(key, it) }
    }
    
    public open class NewInstanceFactory : Factory {
        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)
            }
        }

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

            private object ViewModelKeyImpl : Key<String>
            @JvmField
            val VIEW_MODEL_KEY: Key<String> = ViewModelKeyImpl
        }
    }
}

说明:

先调用构造函数创建ViewModelProvider对象,再调用get()方法获取ViewModel对象。

ComponentActivity类

public class ComponentActivity extends androidx.core.app.ComponentActivity implements
    ViewModelStoreOwner { 

    //ViewModel存储容器
    private ViewModelStore mViewModelStore;
    //ViewModel的创建工厂
    private ViewModelProvider.Factory mDefaultFactory;

    public ComponentActivity() {
        //监听Activity生命周期
        getLifecycle().addObserver(new LifecycleEventObserver() {
            @Override
            public void onStateChanged(@NonNull LifecycleOwner source,
                                       @NonNull Lifecycle.Event event) {
                if (event == Lifecycle.Event.ON_DESTROY) {
                    //Activity在onDestroy时清理ViewModelStore
                    mContextAwareHelper.clearAvailableContext();                    
                    if (!isChangingConfigurations()) {
                        getViewModelStore().clear();
                    }
                }
            }
        });
    }

    @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.");
        }
        ensureViewModelStore();
        return mViewModelStore;
    }

    //创建ViewModelStore对象
    void ensureViewModelStore() {
        if (mViewModelStore == null) {
            NonConfigurationInstances nc =
                (NonConfigurationInstances) getLastNonConfigurationInstance();
            if (nc != null) {
                mViewModelStore = nc.viewModelStore;
            }
            if (mViewModelStore == null) {
                mViewModelStore = new ViewModelStore();
            }
        }
    }

    //屏幕旋转时调用
    @Override
    @Nullable
    public final Object onRetainNonConfigurationInstance() {
        Object custom = onRetainCustomNonConfigurationInstance();
        ViewModelStore viewModelStore = mViewModelStore;
        if (viewModelStore == null) {
            //恢复ViewModelStore对象
            NonConfigurationInstances nc =
                (NonConfigurationInstances) getLastNonConfigurationInstance();
            if (nc != null) {
                viewModelStore = nc.viewModelStore;
            }
        }

        if (viewModelStore == null && custom == null) {
            return null;
        }

        //保存ViewModelStore对象
        NonConfigurationInstances nci = new NonConfigurationInstances();
        nci.custom = custom;
        nci.viewModelStore = viewModelStore;
        return nci;
    }

    static final class NonConfigurationInstances {
        Object custom;
        ViewModelStore viewModelStore;
    }
}

说明:

ComponentActivity类实现了ViewModelStoreOwner接口并实现了getViewModelStore()方法,Activity在创建时生成ViewModelStore对象。

当Activity旋转屏幕导致被销毁时,不仅会调用onSaveInstanceState()方法,还会调用onRetainNonConfigurationInstance()方法,屏幕旋转时保存ViewModelStore对象。

by viewModels()

@MainThread
public inline fun <reified VM : ViewModel> ComponentActivity.viewModels(
    noinline factoryProducer: (() -> Factory)? = null
): Lazy<VM> {
    val factoryPromise = factoryProducer ?: {
        defaultViewModelProviderFactory
    }
    return ViewModelLazy(VM::class, { viewModelStore }, factoryPromise)
}
public class ViewModelLazy<VM : ViewModel> @JvmOverloads constructor(
    private val viewModelClass: KClass<VM>,
    private val storeProducer: () -> ViewModelStore,
    private val factoryProducer: () -> ViewModelProvider.Factory,
    private val extrasProducer: () -> CreationExtras = { CreationExtras.Empty }
) : Lazy<VM> {
    private var cached: VM? = null

    override val value: VM
        get() {
            val viewModel = cached
            return if (viewModel == null) {
                val factory = factoryProducer()
                val store = storeProducer()
                //最终也是通过 ViewModelProvider 创建 ViewModel 实例
                ViewModelProvider(
                    store,
                    factory,
                    extrasProducer()
                ).get(viewModelClass.java).also {
                    cached = it
                }
            } else {
                viewModel
            }
        }

    override fun isInitialized(): Boolean = cached != null
}

数据保存阶段

页面上的数据可以定义为两类:

  • 配置数据:窗口大小、主题资源、多语言字符等。
  • 非配置数据:用户信息、音视频播放信息、异步任务等。

当设备配置发生变更时,需要根据最新的配置重新读取新的数据,因此这部分数据在配置变更后失去意义,无需保存;非配置数据和设备配置没有任何关系,在重建Activity时会丢失,无法快速恢复页面数据,降低用户体验度。

ActivityThread#handleDestroyActivity#

public void handleDestroyActivity(ActivityClientRecord r, boolean finishing, int configChanges,
                                  boolean getNonConfigInstance, String reason) {
    performDestroyActivity(r, finishing, configChanges, getNonConfigInstance, reason);

    if (finishing) {
        ActivityClient.getInstance().activityDestroyed(r.token);
    }
}

ActivityThread#performDestroyActivity

void performDestroyActivity(ActivityClientRecord r, boolean finishing,
                            int configChanges, boolean getNonConfigInstance, String reason) {

    if (getNonConfigInstance) {
        try {
            //调用Activity#retainNonConfigurationInstances(),并存放在ActivityClientRecord
            r.lastNonConfigurationInstances = r.activity.retainNonConfigurationInstances();
        } 
    }
    //回调Activity#onDestroy()
    mInstrumentation.callActivityOnDestroy(r.activity);
}

Activity#retainNonConfigurationInstances()

NonConfigurationInstances retainNonConfigurationInstances() {
    Object activity = onRetainNonConfigurationInstance();
    //间接回调ComponentActivity#onRetainNonConfigurationInstance(),并返回NonConfigurationInstances对象
    HashMap<String, Object> children = onRetainNonConfigurationChildInstances();
    FragmentManagerNonConfig fragments = mFragments.retainNestedNonConfig();

    mFragments.doLoaderStart();
    mFragments.doLoaderStop(true);
    ArrayMap<String, LoaderManager> loaders = mFragments.retainLoaderNonConfig();

    if (activity == null && children == null && fragments == null && loaders == null
        && mVoiceInteractor == null) {
        return null;
    }

    NonConfigurationInstances nci = new NonConfigurationInstances();
    nci.activity = activity;
    nci.children = children;
    nci.fragments = fragments;
    nci.loaders = loaders;
    if (mVoiceInteractor != null) {
        mVoiceInteractor.retainInstance();
        nci.voiceInteractor = mVoiceInteractor;
    }
    //返回NonConfigurationInstances对象
    return nci;
}

Activity#onRetainNonConfigurationInstance()

//此方法交给子Activity实现
public Object onRetainNonConfigurationInstance() {
    return null;
}

androidx.activity.ComponentActivity#onRetainNonConfigurationInstance()

public final Object onRetainNonConfigurationInstance() {
    //mViewModelStore为当前Activity的ViewModelStore
    ViewModelStore viewModelStore = mViewModelStore;

    //如果Activity没有调用getViewModelStore(),那么检查旧Activity传递过来的数据
    if (viewModelStore == null) {
        NonConfigurationInstances nc =
            (NonConfigurationInstances) getLastNonConfigurationInstance();
        if (nc != null) {
            viewModelStore = nc.viewModelStore;
        }
    }

    //viewModelStore为null说明Activity和旧Activity没有ViewModel
    if (viewModelStore == null && custom == null) {
        return null;
    }

    NonConfigurationInstances nci = new NonConfigurationInstances();
    //换成ViewModelStore对象
    nci.viewModelStore = viewModelStore;
    //返回NonConfigurationInstances对象
    return nci;
}

数据恢复阶段

ActivityThread#handleRelaunchActivity()

public void handleRelaunchActivity(ActivityClientRecord tmp,
                                   PendingTransactionActions pendingActions) {
    ActivityClientRecord r = mActivities.get(tmp.token);
    r.activity.mConfigChangeFlags |= configChanges;
    r.mPreserveWindow = tmp.mPreserveWindow;
    r.activity.mChangingConfigurations = true;

    handleRelaunchActivityInner(r, configChanges, tmp.pendingResults, tmp.pendingIntents,
                                pendingActions, tmp.startsNotResumed, tmp.overrideConfig, "handleRelaunchActivity");
}

ActivityThread#handleRelaunchActivityInner()

private void handleRelaunchActivityInner(ActivityClientRecord r, int configChanges,         List<ResultInfo> pendingResults, List<ReferrerIntent> pendingIntents, PendingTransactionActions pendingActions, boolean startsNotResumed, Configuration overrideConfig, String reason) {
    //回调Activity#onPause()
    performPauseActivity(r, false, reason, null /* pendingActions */);
    //回调Activity#onStop()
    callActivityOnStop(r, true /* saveState */, reason);
	//获取Activity的非配置数据
    handleDestroyActivity(r, false, configChanges, true, reason);
	//间接在Activity#attach()传递旧Activity的数据
    handleLaunchActivity(r, pendingActions, customIntent);
}

ActivityThread#handleLaunchActivity

public Activity handleLaunchActivity(ActivityClientRecord r,
                                     PendingTransactionActions pendingActions, 
                                     Intent customIntent) {

    final Activity a = performLaunchActivity(r, customIntent);
    return a;
}

ActivityThread#performLaunchActivity()

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    //创建新的Activity    
    Activity activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
    //创建火获取Application实例
    Application app = r.packageInfo.makeApplication(false, mInstrumentation);
    //传递lastNonConfigurationInstances数据
    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.shareableActivityToken);
    //清空临时变量
    r.lastNonConfigurationInstances = null;
    return activity;
}

Activity#attach()

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,
                  IBinder shareableActivityToken) {
    	//将旧Activity的非配置数据保存
        mLastNonConfigurationInstances = lastNonConfigurationInstances;
}

ComponentActivity#getViewModelStore()

获取ViewModelStore

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

相关文章:

  • 数字逻辑第二章笔记
  • 从开发角度看羊了个羊
  • 我用PaddleOCR把Halcon论坛的OCR帖子试了一遍,结果。。。
  • 微信号怎么改
  • Spring集成Apache Kafka教程
  • 基于SSM实现图书馆座位预约系统
  • java部分排序算法
  • Java8-特性
  • Mybatis-Plus快速入门|比Mybatis更简单好用的ORM框架
  • Java异常的捕获和处理
  • 若依一体式改包名
  • 【机器学习kaggle赛事】泰坦尼克号生存预测
  • 【C进阶】——详解10个C语言中常见的字符串操作函数及其模拟实现
  • vue--面试题
  • HotPlot
  • 深入了解以太坊
  • 「前端」从UglifyJSPlugin强制开启css压缩探究webpack插件运行机制
  • CoolViewPager:即刻刷新,自定义边缘效果颜色,双向自动循环,内置垂直切换效果,想要的都在这里...
  • Java多态
  • java多线程
  • js写一个简单的选项卡
  • Laravel Telescope:优雅的应用调试工具
  • mongodb--安装和初步使用教程
  • php面试题 汇集2
  • Spring Boot快速入门(一):Hello Spring Boot
  • Three.js 再探 - 写一个跳一跳极简版游戏
  • 半理解系列--Promise的进化史
  • 编写高质量JavaScript代码之并发
  • 浅谈JavaScript的面向对象和它的封装、继承、多态
  • 如何解决微信端直接跳WAP端
  • 深入浅出webpack学习(1)--核心概念
  • 事件委托的小应用
  • 微信小程序--------语音识别(前端自己也能玩)
  • 再次简单明了总结flex布局,一看就懂...
  • 格斗健身潮牌24KiCK获近千万Pre-A轮融资,用户留存高达9个月 ...
  • ​​快速排序(四)——挖坑法,前后指针法与非递归
  • # Swust 12th acm 邀请赛# [ E ] 01 String [题解]
  • (Matalb回归预测)PSO-BP粒子群算法优化BP神经网络的多维回归预测
  • (NO.00004)iOS实现打砖块游戏(九):游戏中小球与反弹棒的碰撞
  • (办公)springboot配置aop处理请求.
  • (分享)自己整理的一些简单awk实用语句
  • (附源码)spring boot基于Java的电影院售票与管理系统毕业设计 011449
  • (幽默漫画)有个程序员老公,是怎样的体验?
  • (转)可以带来幸福的一本书
  • ****** 二十三 ******、软设笔记【数据库】-数据操作-常用关系操作、关系运算
  • .\OBJ\test1.axf: Error: L6230W: Ignoring --entry command. Cannot find argumen 'Reset_Handler'
  • .NET Core SkiaSharp 替代 System.Drawing.Common 的一些用法
  • .NET WebClient 类下载部分文件会错误?可能是解压缩的锅
  • .NET Windows:删除文件夹后立即判断,有可能依然存在
  • .NET 将混合了多个不同平台(Windows Mac Linux)的文件 目录的路径格式化成同一个平台下的路径
  • .Net的C#语言取月份数值对应的MonthName值
  • .Net下的签名与混淆
  • .py文件应该怎样打开?
  • @Async注解的坑,小心
  • [ C++ ] STL---string类的使用指南