ViewModel使用方法、原理分析(一)

306 阅读1分钟

Jetpack系列:
Lifecycle使用方法、原理分析 - 掘金 (juejin.cn)
LiveData使用方法、原理分析 - 掘金 (juejin.cn)
ViewModel使用方法、原理分析(一) - 掘金 (juejin.cn)
ViewModel使用方法、原理分析(二) - 掘金 (juejin.cn)
自定义View中获取ViewModel - 掘金 (juejin.cn)

ViewModel基本使用

/**
* 携带自定义参数的ViewModel,创建时需要创建自定义ViewModelProvider.Factory
*
**/
class CustomViewModel(name: String?):ViewModel() {
    private val _data1 = MutableLiveData("A")
    val data1:LiveData<String> = _data1
}

/**
* ComponentActvity、Fragment默认的SavedStateViewModelFactory
* 将Intent.getBundle() & Fragment.getArugment()作为参数在ViewModel反射时传递
* 优点:可获取Activity跳转时携带的参数
**/
class CustomViewModel(savedStateHandle: SavedStateHandle?):ViewModel() {
    private val _data1 = MutableLiveData("A")
    val data1:LiveData<String> = _data1
    
    init {
       val param = savedStateHandle.get<String>("param")
       Log.d("TAG", "===========param:$param")
    }
}



class CustomViewActivity:ComponentActivity() {
    //方法1:Kotlin 语法糖形式创建ViewModel,还是调用ViewModelProvider.get()
    private val viewModel by viewModels<CustomViewModel>()
    
    //需注意方法2&方法3 初始化操作需要在Activity OnCreate之后执行
    //方法2:ViewModelProvider创建ViewModel,不带工厂Factory,不能携带初始化参数
    private val viewModel1 = ViewModelProvider(this)[CustomViewModel::class.java]
    
    //方法3:ViewModelProvider创建ViewModel,带工厂Factory,可携带初始化参数
    private val viewModel2 = ViewModelProvider(this, CustomViewModelFactory())[CustomViewModel::class.java]
    private class CustomViewModelFactory() : ViewModelProvider.Factory{
        private val name = "CustomViewModel"
        override fun <T : ViewModel> create(modelClass: Class<T>): T {
            return CustomViewModel("") as T
        }
    }
}

ViewModel原理分析

ViewModelStore

ViewModelStore 一种缓存机制,通过键值对的形式来缓存 ViewModel 对象,key取值为ViewModel类名

DEFAULT_KEY = "androidx.lifecycle.ViewModelProvider.DefaultKey"+ modelClass.canonicalName

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

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

ViewModelStoreOwner

ComponentActivity为其实现类(AppCompatActivity继承FragmentActivity继承ComponentActivity),实现了 ViewModelStoreOwner 接口的组件内部会自动创建 ViewModelStore, ViewModel 对象会缓存到 ViewModelStore 这些组件产生了绑定关系, NonConfigurationInstances是实现Activity配置发生改变时,ViewModel保存数据的关键

public interface ViewModelStoreOwner {
    /**
     * Returns owned {@link ViewModelStore}
     *
     * @return a {@code ViewModelStore}
     */
    @NonNull
    ViewModelStore getViewModelStore();
}


/**
 * ComponentActivity类中关于实现ViewModelOwner接口,ensureViewModelStore()初始化ViewModelStore
 * 
 *
 */
@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;
}

@SuppressWarnings("WeakerAccess") /* synthetic access */
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();
        }
    }
}

ViewModelProvider

用来创建ViewModel,通过Android官方源码提供的创建ViewModel作为入口进行分析

val viewmodel: MyViewModel by viewmodels()

/**
* CompentActivity扩展函数,可以传入Factory作为参数用于创建ViewModel,CompentActivity实现
* HasDefaultViewModelProviderFactory接口,可以获取默认Factory对象为SaveStateViewModelFactory
* 
**/
@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(
                    store,
                    factory,
                    extrasProducer()
                ).get(viewModelClass.java).also {
                    cached = it
                }
            } else {
                viewModel
            }
        }

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

ViewModelProvider内部有个工厂接口,通过反射形式创建ViewModel对象,创建过程如下:

@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)
}

@Suppress("UNCHECKED_CAST")
@MainThread
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) }
}

/**
* 工厂类接口 
* 
**/
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)
}

/**
* 工厂类接口两个自带实现类,
* NewInstanceFactory、AndroidViewModelFactory分别用于创建自定义ViewModel、AndroidViewModel 
* 
**/
public open class NewInstanceFactory : Factory {
    @Suppress("DocumentExceptions")
    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
    }
}

public open class AndroidViewModelFactory
private constructor(
    private val application: 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)) {
            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
    }
}

SaveStateViewModelFactory

CompentActivity、Fragment中持有SaveStateViewModelFactory,通过SaveStateViewModelFactory生成ViewModel,携带Intent&Argument参数,用与创建携带SavedStateHandle的ViewModel


private val ANDROID_VIEWMODEL_SIGNATURE = listOf<Class<*>>(
    Application::class.java,
    SavedStateHandle::class.java
)
private val VIEWMODEL_SIGNATURE = listOf<Class<*>>(SavedStateHandle::class.java)



fun <T : ViewModel> create(key: String, modelClass: Class<T>): T {
    // empty constructor was called.
    if (lifecycle == null) {
        throw UnsupportedOperationException(
            "SavedStateViewModelFactory constructed with empty constructor supports only " +
                "calls to create(modelClass: Class<T>, extras: CreationExtras)."
        )
    }
    val isAndroidViewModel = AndroidViewModel::class.java.isAssignableFrom(modelClass)
    val constructor: Constructor<T>? = if (isAndroidViewModel && application != null) {
        findMatchingConstructor(modelClass, ANDROID_VIEWMODEL_SIGNATURE)
    } else {
        findMatchingConstructor(modelClass, VIEWMODEL_SIGNATURE)
    }
    // doesn't need SavedStateHandle
    if (constructor == null) {
        // If you are using a stateful constructor and no application is available, we
        // use an instance factory instead.
        return if (application != null) factory.create(modelClass)
            else instance.create(modelClass)
    }
    val controller = LegacySavedStateHandleController.create(
        savedStateRegistry, lifecycle, key, defaultArgs
    )
    val viewModel: T = if (isAndroidViewModel && application != null) {
        newInstance(modelClass, constructor, application!!, controller.handle)
    } else {
        newInstance(modelClass, constructor, controller.handle)
    }
    viewModel.setTagIfAbsent(
        AbstractSavedStateViewModelFactory.TAG_SAVED_STATE_HANDLE_CONTROLLER, controller
    )
    return viewModel
}

internal fun <T : ViewModel?> newInstance(
    modelClass: Class<T>,
    constructor: Constructor<T>,
    vararg params: Any
): T {
    return try {
        constructor.newInstance(*params)
    } catch (e: IllegalAccessException) {
        throw RuntimeException("Failed to access $modelClass", e)
    } catch (e: InstantiationException) {
        throw RuntimeException("A $modelClass cannot be instantiated.", e)
    } catch (e: InvocationTargetException) {
        throw RuntimeException(
            "An exception happened in constructor of $modelClass", e.cause
        )
    }
}