JetPack之ViewModel使用和原理

部分更细致的流程,概过

Activity重建后ViewModel内的数据不受影响原因?

ViewModelStore 存储多个ViewModel在内部map中,在配置改变时ViewModelStore将会被封装到Activity的内部类NonConfigurationInstances中,然后储存到ActivityThread类中的应用数据结构ActityClientRecord中,重建之后,handleReLaunch流程依次经过赋值将NonconfigtionInstaces赋值给ActivityClientRecord,然后接着通过activity.attach将上面赋值重写设置到Activity中,所以还是上次的销毁时的NonCongifurationInstances即ViewModelStore。这才是ViewModel不受配置改变影响的本质。

分析
ViewModelStoreOwner
public interface ViewModelStoreOwner {

    public val viewModelStore: ViewModelStore
}
ViewModelStore
public open class ViewModelStore {

    //用来存储viewmodel
    private val map = mutableMapOf<String, ViewModel>()

    /**  */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public fun put(key: String, viewModel: ViewModel) {
        val oldViewModel = map.put(key, viewModel)
        oldViewModel?.clear()
    }

    /** Returns the `ViewModel` mapped to the given `key` or null if none exists. */
    /**  */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public operator fun get(key: String): ViewModel? {
        return map[key]
    }

    /**  */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public fun keys(): Set<String> {
        return HashSet(map.keys)
    }

    /** Clears internal storage and notifies `ViewModel`s that they are no longer used. */
    public fun clear() {
        for (vm in map.values) {
            vm.clear()
        }
        map.clear()
    }
}
ViewModelProvider
public expect class ViewModelProvider {

    @MainThread public operator fun <T : ViewModel> get(modelClass: KClass<T>): T
     */
    @MainThread public operator fun <T : ViewModel> get(key: String, modelClass: KClass<T>): T

    /** Implementations of `Factory` interface are responsible to instantiate ViewModels. */
    public interface Factory {

        public open fun <T : ViewModel> create(
            modelClass: KClass<T>,
            extras: CreationExtras,
        ): T
    }

    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public open class OnRequeryFactory {
        public open fun onRequery(viewModel: ViewModel)
    }

    public companion object {
        public fun create(
            owner: ViewModelStoreOwner,
            factory: Factory = ViewModelProviders.getDefaultFactory(owner),
            extras: CreationExtras = ViewModelProviders.getDefaultCreationExtras(owner),
        ): ViewModelProvider

        public fun create(
            store: ViewModelStore,
            factory: Factory = DefaultViewModelProviderFactory,
            extras: CreationExtras = CreationExtras.Empty,
        ): ViewModelProvider

        public val VIEW_MODEL_KEY: CreationExtras.Key<String>
    }
}
ViewModelProviderImpl
internal class ViewModelProviderImpl(
    private val store: ViewModelStore,
    private val factory: ViewModelProvider.Factory,
    private val defaultExtras: CreationExtras,
) {

    private val lock = SynchronizedObject()

    @Suppress("UNCHECKED_CAST")
    internal fun <T : ViewModel> getViewModel(
        modelClass: KClass<T>,
        key: String = ViewModelProviders.getDefaultKey(modelClass),
    ): T {
        return synchronized(lock) {
            如果ComponentActivity中的ViewModelStore中存在当前modelClass的实例
        //那就直接返回。发生场景应配置更改重建页面时,拿到的还是之前的viewModel。
            val viewModel = store[key]
            if (modelClass.isInstance(viewModel)) {
                if (factory is ViewModelProvider.OnRequeryFactory) {
                    factory.onRequery(viewModel!!)
                }
                return@synchronized viewModel as T
            }
            //否则通过factory.create进行首次创建viewModel并最后通过store.put()
        	//将viewModel储存到ComponentActivity的全局变量viewModelStore中。

            val modelExtras = MutableCreationExtras(defaultExtras)
            modelExtras[ViewModelProviders.ViewModelKey] = key

            return@synchronized createViewModel(factory, modelClass, modelExtras).also { vm ->
                store.put(key, vm)
            }
        }
    }
}

internal expect fun <VM : ViewModel> createViewModel(
    factory: ViewModelProvider.Factory,
    modelClass: KClass<VM>,
    extras: CreationExtras,
): VM
Activity和ComponentActivity

Activity 孩子类 ComponentActivity 重写了 onRetainNonConfigurationInstance 方法,方法中将ComponentActivity中的_viewModel赋值给了NonConfigurationInstances,返回给了这里。当屏幕旋转之后再 ActivityThread 中执行 performDestroyActivity时 ,通过 r.lastNonConfigurationInstances = r.activity.retainNonConfigurationInstances(); 拿到Activity 这里的 NonConfigurationInstances 赋值给 r(ActivityClientRecord),最终实现了ComponentActivity 中的 _viewModelStore 被保存到了 ActivityClientRecord中。

当配置发生改变,ActivityThread 执行到 performDestoryActivity之后,通过r.activity.retainNonConfigurationInstances() 调用了Activity 内部的 retainNonConfigurationInstances 方法,而在方法里面Object activity = onRetainNonConfigurationInstance() 被 ComponentActivity 所覆写的 onRetainNonConfigurationInstance 且返回了ComponentActivity 中分装了 _viewModel的NonConfigurationInstances。最终分装为Activity中的 NonConfigurationInstances 赋值给了r.lastNonConfigurationInstances。需要了解其ComponentActivity 和 Activity中的NonConfigurationInstances不是同一个类。

//ComponentActivity
open class ComponentActivity():Activity{
    //用于储存viewModelStore的配置容器类
    internal class NonConfigurationInstances {
        var custom: Any? = null
        var viewModelStore: ViewModelStore? = null
    }

    @Suppress("deprecation")
    final override fun onRetainNonConfigurationInstance(): Any? {
        // Maintain backward compatibility.
        val custom = onRetainCustomNonConfigurationInstance()
        var viewModelStore = _viewModelStore
        if (viewModelStore == null) {
            // No one called getViewModelStore(), so see if there was an existing
            // ViewModelStore from our last NonConfigurationInstance
            val nc = lastNonConfigurationInstance as NonConfigurationInstances?
            if (nc != null) {
                viewModelStore = nc.viewModelStore
            }
        }
        if (viewModelStore == null && custom == null) {
            return null
        }
        val nci = NonConfigurationInstances()
        nci.custom = custom
        nci.viewModelStore = viewModelStore
        return nci
    }
}


public class Activity extends...{
    //孩子ComponentActivity重写了此方法,并将ComponentActivity
    //中的_viewModel赋值给了NonConfigurationInstances,返回给了这里。
    public Object onRetainNonConfigurationInstance() {
        return null;
    }
    //需要区分CompnentActivity中的NonConfigurationInstances不是同一个类。
    static final class NonConfigurationInstances {
        Object activity;
        HashMap<String, Object> children;
        FragmentManagerNonConfig fragments;
        ArrayMap<String, LoaderManager> loaders;
        VoiceInteractor voiceInteractor;
    }

    //当屏幕旋转之后再ActivityThread 中执行 performDestroyActivity时
    //通过 r.lastNonConfigurationInstances = r.activity.retainNonConfigurationInstances();
    //拿到Activity这里的NonConfigurationInstances赋值给r(ActivityClientRecord)
    NonConfigurationInstances retainNonConfigurationInstances() {
        Object activity = onRetainNonConfigurationInstance();
        HashMap<String, Object> children = onRetainNonConfigurationChildInstances();
        FragmentManagerNonConfig fragments = mFragments.retainNestedNonConfig();

        // We're already stopped but we've been asked to retain.
        // Our fragments are taken care of but we need to mark the loaders for retention.
        // In order to do this correctly we need to restart the loaders first before
        // handing them off to the next activity.
        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;
        }
        return nci;
    }
    //第十步
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    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) {
        attachBaseContext(context);

        mFragments.attachHost(null /*parent*/);
        mActivityInfo = info;

        //.....省略其他代码......  
        //第11步
        mLastNonConfigurationInstances = lastNonConfigurationInstances;
        //.....省略其他代码...... 
    }

}
当配置发生改变

ActivityManagerService 接收到重新创建的消息,会在performDestroyActivity 内部给当前的ActivityClientRecord 赋值为当前的NonConfigurationInstances,实现了viewmodel的存储。

ensureViewModelStore方法,其内部通过lastNonConfigurationInstance先获取是否配置发生变化之后恢复拿到nc.viewModelStore,否则新建ViewModelStore() 并保存在了 ComponentActivity全局变量_viewModelStore中

ViewModel的使用和具体调用细节
ViewModel对象获取
//owner代表ViewModelStoreOwner
val viewModel = ViewModelProvider(owner).get(ActivityViewModel::class.java)

//factory代表Factory
val viewModel = ViewModelProvider(owner, factory).get(ActivityViewModel::class.java)

//store代表ViewModelStore
val viewModel = ViewModelProvider(store, factory).get(ActivityViewModel::class.java)

//owner内的ViewModelStore哪里来????
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;
}



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

@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")
    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
    // AGP has some desugaring issues associated with compileOnly dependencies so we need to
    // fall back to the other create method to keep from crashing.
    return try {
        factory.create(modelClass, extras)
    } catch (e: AbstractMethodError) {
        factory.create(modelClass)
    }.also { store.put(key, it) }
}

owner内的ViewModelStore哪里来????
ComponentActivity中
private ViewModelStore mViewModelStore;
...
@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();  //确保mViewModelStore被实例化
    return mViewModelStore;
}

@SuppressWarnings("WeakerAccess") /* synthetic access */
void ensureViewModelStore() {
    if (mViewModelStore == null) {
        //先看是不是activity异常销毁重建后需要恢复viewModel数据的情况
        NonConfigurationInstances nc =
                (NonConfigurationInstances) getLastNonConfigurationInstance();
        if (nc != null) {
            // Restore the ViewModelStore from NonConfigurationInstances
            mViewModelStore = nc.viewModelStore;
        }
        
        //如果不是需要恢复数据,就new出一个ViewModelStore对象。
        if (mViewModelStore == null) {
            mViewModelStore = new ViewModelStore();
        }
    }
}

Fragment中
public ViewModelStore getViewModelStore() {
    if (mFragmentManager == null) {
        throw new IllegalStateException("Can't access ViewModels from detached fragment");
    }
    ...
    return mFragmentManager.getViewModelStore(this);
}



//FragmentManager内的方法
private FragmentManagerViewModel mNonConfig;
...
ViewModelStore getViewModelStore(@NonNull Fragment f) {
    return mNonConfig.getViewModelStore(f);
}

//FragmentManagerViewModel中的方法
private final HashMap<String, ViewModelStore> mViewModelStores = new HashMap<>();
...
ViewModelStore getViewModelStore(@NonNull Fragment f) {
    ViewModelStore viewModelStore = mViewModelStores.get(f.mWho);
    if (viewModelStore == null) {
        viewModelStore = new ViewModelStore();
        mViewModelStores.put(f.mWho, viewModelStore);
    }
    return viewModelStore;
}


结论

Fragment的ViewModel存储在它对应的ViewModelStore中,ViewModelStore存储在FragmentManagerViewModel中的map中,而FragmentManagerViewModel存储在FragmentManager所关联的Activity的ViewModelStore中。

viewModel的清除
getLifecycle().addObserver(new LifecycleEventObserver() {
        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) {
            if (event == Lifecycle.Event.ON_DESTROY) {
                // Clear out the available context
                mContextAwareHelper.clearAvailableContext();
                
                // isChangingConfigurations()方法返回值表示是否是配置变更销毁重建,通过配置修改来确定是否进行销毁viewModel
                if (!isChangingConfigurations()) {
                    getViewModelStore().clear();
                }
            }
        }
    });
参考

Jetpack ViewModel (源码分析) 面试 (qq.com)

ViewModel - 掘金 (juejin.cn)

  • 9
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值