Java教程

ViewModel源码分析

本文主要是介绍ViewModel源码分析,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
Activity中ViewModel实例的获取
private val mViewModel: DataTestViewModel by viewModels()

可见viewModel的获取是通过viewModels代理类实现的,我们继续跟进

  • 通过代码查看,我们看到viewModels实际上是ComponentActivity的一个内联扩展方法
@MainThread
inline fun <reified VM : ViewModel> ComponentActivity.viewModels(
    noinline factoryProducer: (() -> Factory)? = null
): Lazy<VM> {
    //  1 获取factoryPromise,默认为null,使用defaultViewModelProviderFactory
    val factoryPromise = factoryProducer ?: {
        defaultViewModelProviderFactory
    }
    //  2 通过 ViewModelLazy 获取ViewModel实例
    return ViewModelLazy(VM::class, { viewModelStore }, factoryPromise)
}
1、ComponentActivity 中 getDefaultViewModelProviderFactory
 @NonNull
    @Override
    public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {
        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 (mDefaultFactory == null) {
            // 创建defaultFactory
            mDefaultFactory = new SavedStateViewModelFactory(
                    getApplication(),
                    this,
                    getIntent() != null ? getIntent().getExtras() : null);
        }
        return mDefaultFactory;
    }
  • 构造传参数,通过工厂类SavedStateViewModelFactory创建ViewModelFactory类型实例作为mDefaultFactory

  • SavedStateViewModelFactory构造获取SavedStateViewModelFactory

  @SuppressLint("LambdaLast")
    public SavedStateViewModelFactory(@NonNull Application application,
            @NonNull SavedStateRegistryOwner owner,
            @Nullable Bundle defaultArgs) {
        mSavedStateRegistry = owner.getSavedStateRegistry();
        mLifecycle = owner.getLifecycle();
        mDefaultArgs = defaultArgs;
        mApplication = application;
        mFactory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
    }
  • SavedStateViewModelFactory中create()方法
    通过create方法创建ViewModel实例
 @NonNull
    @Override
    public <T extends ViewModel> T create(@NonNull String key, @NonNull Class<T> modelClass) {
        boolean isAndroidViewModel = AndroidViewModel.class.isAssignableFrom(modelClass);
        Constructor<T> constructor;
        if (isAndroidViewModel) {
            constructor = findMatchingConstructor(modelClass, ANDROID_VIEWMODEL_SIGNATURE);
        } else {
            constructor = findMatchingConstructor(modelClass, VIEWMODEL_SIGNATURE);
        }
        // doesn't need SavedStateHandle
        if (constructor == null) {
        // 通过mFactory直接创建viewModel
            return mFactory.create(modelClass);
        }

        SavedStateHandleController controller = SavedStateHandleController.create(
                mSavedStateRegistry, mLifecycle, key, mDefaultArgs);
        try {
            T viewmodel;
            if (isAndroidViewModel) {
                // 通过构造方法实例化viewModel
                viewmodel = constructor.newInstance(mApplication, controller.getHandle());
            } else {
                viewmodel = constructor.newInstance(controller.getHandle());
            }
            viewmodel.setTagIfAbsent(TAG_SAVED_STATE_HANDLE_CONTROLLER, controller);
            return viewmodel;
        } catch (IllegalAccessException e) {
            throw new RuntimeException("Failed to access " + modelClass, e);
        } catch (InstantiationException e) {
            throw new RuntimeException("A " + modelClass + " cannot be instantiated.", e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException("An exception happened in constructor of "
                    + modelClass, e.getCause());
        }
    }

通过create方法我们可以知道viewModel的创建有两种方式:
1、 通过mFactory.create(modelClass)方法获取
2、通过constructor.newInstance(mApplication, controller.getHandle())获取

2、通过ViewModelLazy(VM::class, { viewModelStore }, factoryPromise)构建ViewModel实例
  • 通过代码我们看到首先通过cached对viewModel赋值,如果viewModel为空,通过ViewModelProvider获取viewmodel并进行缓存。不为空时,直接将缓存的viewmodel返回
class ViewModelLazy<VM : ViewModel> (
    private val viewModelClass: KClass<VM>,
    // 1 viewModelStore获取
    private val storeProducer: () -> ViewModelStore,
    // 2 factoryProducer获取
    private val factoryProducer: () -> ViewModelProvider.Factory
) : Lazy<VM> {
    private var cached: VM? = null

    override val value: VM
        get() {
            val viewModel = cached
            return if (viewModel == null) {
                //  获取factory
                val factory = factoryProducer()
                //  获取store
                val store = storeProducer()
                // 3 通过ViewModelProvider传递参数factory和store获取viewmodel
                ViewModelProvider(store, factory).get(viewModelClass.java).also {
                    // 缓存viwemodel
                    cached = it
                }
            } else {
                viewModel
            }
        }
    
    override fun isInitialized() = cached != null
}
2.1 viewModelStore的获取
  • 源码追溯到ComponentActivity中getViewModelStore方法
  /**
     * Returns the {@link ViewModelStore} associated with this activity
     * <p>
     * Overriding this method is no longer supported and this method will be made
     * <code>final</code> in a future version of ComponentActivity.
     *
     * @return a {@code ViewModelStore}
     * @throws IllegalStateException if called before the Activity is attached to the Application
     * instance i.e., before onCreate()
     */
    @NonNull
    @Override
    public ViewModelStore getViewModelStore() {
        // application为空时,也就是在activity添加到应用之前,获取viewModelStore抛出异常
        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获取viewModelStore
            NonConfigurationInstances nc =
                    (NonConfigurationInstances) getLastNonConfigurationInstance();
            if (nc != null) {
                // Restore the ViewModelStore from NonConfigurationInstances
                mViewModelStore = nc.viewModelStore;
            }
            //  1 通过NonConfigurationInstances获取viewModelStore失败,直接创建ViewModelStore
            if (mViewModelStore == null) {
            // 2
                mViewModelStore = new ViewModelStore();
            }
        }
        return mViewModelStore;
    }
  • 2.1.1 nc获取
  @Nullable
    public Object getLastNonConfigurationInstance() {
        return mLastNonConfigurationInstances != null
                ? mLastNonConfigurationInstances.activity : null;
    }

那既然通过NonConfigurationInstances中viewModelStore可以获取viewModelStore,那么mLastNonConfigurationInstances是什么时候赋值的呢?我们继续跟进

  • Activity中attach方法

通过跟进源码我们查看mLastNonConfigurationInstances赋值是通过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) {
            ... 省略非关联代码
             mLastNonConfigurationInstances = lastNonConfigurationInstances;
  • private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent)

继续跟进我们知道是从ActivityThread中performLaunchActivity方法中调用了activity的attach方法

 private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
 ... 省略非关键代码
 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);

通过代码我们发现lastNonConfigurationInstances赋值是通过ActivityClientRecord获取的

  • nc.viewModelStore;
 static final class NonConfigurationInstances {
        Object custom;
        ViewModelStore viewModelStore;
    }
  • 2.1.2 通过new方式创建ViewModelStore类,用于存储key,value键值对
public class ViewModelStore {
    
    // 内部map
    private final HashMap<String, ViewModel> mMap = new HashMap<>();

    // 存储key,viewModel 键值
    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();
    }
}
3、ViewModelProvider(store, factory).get(viewModelClass.java)方法
  • ViewModelProvider中get方法
  @NonNull
    @MainThread
    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");
        }
        // 1
        return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
    }

继续跟进 get方法

  • get(DEFAULT_KEY + “:” + canonicalName, modelClass);
   @SuppressWarnings("unchecked")
    @NonNull
    @MainThread
    public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
        // 通过mViewStore键查询获取viewModel
        ViewModel viewModel = mViewModelStore.get(key);

        if (modelClass.isInstance(viewModel)) {
            // OnRequeryFactory类型factory
            if (mFactory instanceof OnRequeryFactory) {
                ((OnRequeryFactory) mFactory).onRequery(viewModel);
            }
            // 直接返回viewModel
            return (T) viewModel;
        } else {
            //noinspection StatementWithEmptyBody
            if (viewModel != null) {
                // TODO: log a warning.
            }
        }
        // KeyedFactory类型
        if (mFactory instanceof KeyedFactory) {
            viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
        } else {
            viewModel = (mFactory).create(modelClass);
        }
        // 存储
        mViewModelStore.put(key, viewModel);
        return (T) viewModel;
    }

通过mViewModelStore的get的键查询viewModel实例,并根据传入的mFactory类型不同来做不同的处理

1、传入的modelClass是与viewModel实例相同,并且mFactory是OnRequeryFactory类型,通过查询的方式获取viewModel
2、传入的mFactory是KeyedFactory类型时,通过KeyedFactory的create方法创建viewModel
3、非上述两种factory时直接调用mFactory的create方法创建veiwModel
4、创建完成viewModel将viewModel存储到mViewModelStore中

4、流程图:

在这里插入图片描述

  • 参考:https://www.jianshu.com/p/99008e51afb4
这篇关于ViewModel源码分析的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!