前面文章说过,viewModels是fragment的扩展程序里的,效果便是获取ViewModel实例,主要有2个效果,一个是懒加载获取单例,一个java难学吗是在Activity或许Fragment生命周期内获取实例,那么怎样完毕的呢,直接看源码

运用

比如我在登录页,在Activity中需求获取登录的ViewModel:

  • 直接运用viewModel源码年代训练怎样样s函数,参数传递一个工厂。
private源码 val loginViewModel : LoginVjavascriptiewModel by viewModels {
InjectorUtjava语言ils.provide源码是什么意思Logjava模拟器inViewModelFactory(this)
}
  • 供给一个ViewModel工厂。
/**
* 供给登录页逻辑的ViewModappstoreelFactory
* */java集结
fappleun provideLoginViewModelFactory(context: Context): LoginViewMo源码是什么意思delFactory{
return LoginViewModelFactory(getLoginRepository())
}
  • 根据该ViewModel所需求的RepoAPPsitory来创立一个ViewapplicationModel。
class LoginViewModelFactory(private val loginRepository: LoginReposapplicationitory)
: ViewModelProvider.NewInstanceFactappstoreory() {
@S源码是什么意思uppress("UNCHECKED_CAST")
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return LoginViewModel(loginRepository) as T
}
}

源码分析

1、先看viewModels源码以及解析:

@MainThread
inline fun <reified源码年代训练怎样样 VM : ViewModel> Comp源码年代onejava集结ntActivity.viewModels(
noinline facto源码编辑器ryProducer: (() -> Factory)? = null
): Lazy&ljava怎样读t;VM> {
val factoapplicationryPromise = factoryProducer ?: {
defaultViewModelProviderFactory
}
return ViewModelLazy(VM::class, { viewModelStore }, factoryPromise)
}
  • 首要类的注释:
Returns a [L源码精灵azy] delegate to access the Compo源码编辑器nentActivity's ViewMod源码年代训练怎样样el, if [factoryProducer]
is specified then [ViewModelProvijava模拟器der.Facapprovetory] returned by it will be used
to create [ViewModeJaval] first time.

回来一个Lazy的实例来拜访这个Activity的ViewModel,假设factoryProducer即工厂生产者被指明,那么然后ViappstoreewModelProviAPPder.Factory会被回来java开发,同时会先运用这个实例来创立ViewModel实例。

  • 再看调用机遇:
This property can be accessed only源码网站 after the Activity is attached to the Application,
and acce源码是什么意思ss prior to that will result in IllegalArgumentException.

当Activity是attached时,这个特点是能够拜访源码的,提前拜访会报反常。

2、合作appreciate前面所说的注释java怎样读,我们这儿需求一个ViewModeljavascriptProvider.Factory实例,那么这儿也直接运用NeJavawInstanceFactory来完毕,直接看代码:

class LoginViewModelFacto源码买卖网站源码ry(prijava面试题vate val loginRepository: LoginRepository)
: ViewMAPPodelProvider.NewInstanceFactory() {
@Suppress(源码年代训练怎样样"UNapproachCHECKED_CAST源码编辑器")
override fun <T : ViewModel?> create(modelClass: Class<T>)appearance: T {
return LoginVijava语言ewModeappointmentl(loginRepository) as T
}
}

这儿直接回来了LoginViewModel实例。

3、懒加载和单例的完毕,在1中我们能够发现调用了一个3参数的办法,我们来看一下代码:

class ViewModelLazy<VM : ViewModel> (
private val viewModelClass: KClass<VM>app是什么意思,
private val storePjava开发roducer: () -> ViewModelStore,
private val factjava集结oryProducer: () -> ViewModelProvider.Factory
) : Lazy<VMjavascript> {
private var cached: VM? = null
override val value: VM
get() {
val viewModel = cached
r源码网站eturn if (viewModel == nullJava) {
val factorapproachy = factoryProducer()
val store = storeProducer()
ViewModelProvider(sapp是什么意思tore, fappreciateactory).get(viewModelClass.japproveava).also {
cached = it
}
} else {
viewModel
}
}
override fun isInitialize源码之家d() = cached != nu源码编辑器ll
}
  • 这儿注释有句非常重要的话:
Returnsappear an existing View源码编辑器Model源码本钱 or creates a new one in the scope (usually, a fragment or
an activity), associated with this `ViJavaewModelProvider`.

回来一个现有的ViewModel实例或许创源码网站建一个实例,在必定规划内(frajava集结gment或许activity),这个就表明这个实例我不是随意创立的,是和生命周期有关的。

  • 这儿完毕延迟初始化的源码资源站办法还是比较值的学习的,往后有源码精灵需求能够学习。
  • 当viewModel实例为空时,究竟调用ViewModelProvider办法来获取。

4、ViewModelProvider代java怎样读码解析:

public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
mFactory = factory;
mViewModelStore = store;
}

这儿会创立一个VieapplicationwModelProvider实例,有2个参数,第一个factory便是用来创立ViewModel实例的工厂实例,第二个store是保存ViewModel实例的集结,这儿就要留心了,来看一下这个store保存的规划,究竟它不能保存一个ViewModel太久,比如我Activity都被毁掉了,这个store必定不能再保存这个Activity相关的ViewModel了,

public ViewModelStore getVie源码是什么意思wModelStore() {
if (getApplication() ==app是什么意思 null) {
throw new IllegalStateException("Your activity is not yet attached to the "
+ "Application instance. You can't reques源码t ViewjavascriptModel before onCreate cappearanceall.");
}
if (mViewMojava开发delStore == null) {
NonConfigurationInstances nc =
(NonCappreciateonfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
// Rappointmentestore the ViewM源码编辑器odelStore from NonConfigurationI源码之家nstances
mViewModelStore = nc.viewModelStore;
}
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore()源码是什么意思;
}
}
return mViewModelStor源码编辑器e;
}

不出意外,这个store是和activity相关联的,它便是一个HashMap:

public class ViewMod源码年代elStore {
private final HashM源码编辑器ap&java面试题lt;String, ViewModel> mMap = new HashMajava难学吗p<>();
fiapplenal void put(String key, ViewModel viewModel) {
ViewModel olapplicationdViewModel = mMap.put(keappley, viewModel);
if (oldVappleiewModel != 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();Java
}
}

其中有个clearappreciate办法,依照期望必定是在activity毁掉的时分调用,来看一下Activity的代码:

getLifecycle().addObserver(new LifecycleEventObserver() {
@Override
public void onStateChanged(@NonNull LifecycleOwner sjava面试题ource,
@java面试题NonNull Lifecycle.Evapproveent event) {
if (event == Lifecycle.Event.ON_DESTROY) {
if (!isChangingConfigurations()) {appstore
getViewModelStore().clear();
}
}
}
});

也的确如此。

5、从ViewModelProvider中get出需求的ViewModel,依照之前的逻辑,一个Vjava怎样读ieapprovewModelProvider对应着一个factoryjava初学和一个Activity共有的store,所以必定也是依照这种次序来获java怎样读取:

public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
ViewModel viewModel = mViewModelStore.get(key);
if (modelClass.isInstance(v源码iewModel)) {
if (mFactory instanceof OnRequeryFactory) {
((OnRequeryFactory) mFajava开发ctory).onRequery(viewModel);
}
return (T) viewModel;
} else {
//noinspection StatementWithEmptyBody
if (viewModel != null) {
// TOapproachDO: log a warning.
}
}
if (mFactory instancAPPeof KeyedFactory) {
viewModappearanceel = ((KeyedFactory)源码编辑器 (mFactory)).create(key, modelClass);
} else {
viewModel = (mFactory).create(modelClass);
}
mViewModelStore.put(key, viewModel);
retur源码网站n (T) viewModel;
}
  • 这儿也是会先从store中取出,假设没有的话再通过factory来创app是什么意思建,然后刺进到HashMap中。
  • 这儿还会有个新的需求,比如我在Activity A的A处源码精灵获取到一个ViewModel实例,但是在B处也获取时,需求进行修正一下,这时能够运用OnRequeryFactory来完毕。

总结

获取ViewModel实例通过这个办法不只能够完毕单例懒加载java怎样读,内部还完毕了HashMap来达到在必定sco源码是什么意思pe保存实例的效果,能够防止内存占用。