何时调用 onCleared 的视图模型

ViewModel 是独立于活动/片段生命周期,还是仅仅独立于它们的配置更改。什么时候它们不再存在,随后的 onCleared ()方法调用。 ViewModel 可以与其他活动共享吗?

一种情况:

Activity1+viewModel1--->(rotation)--->Activity1+viewModel1
--->(launch Intent)--->Activity2+viewModel1

这种分享是否可行,是否是一种好的做法。

此外,由于应用程序的生命周期回调,onPace-> onStop-> onDestroy 对两者都是相同的

1. 活动旋转和

活动结束时,

ViewModel 如何在内部找到调用 onCleared 并最终结束其生命周期的合适时间。


调查结果 :

ViewModel 在内部使用 holderFragment 来保存活动的实例,并使用 setRetainInstance 方法(如片段)来说明配置更改。

资料来源: 潜入机器人内部-视图模型-体系结构-组件

enter image description here

59834 次浏览

Are ViewModels independent of activity/fragment lifecycles or just their configuration changes.

ViewModels (VMs) are independent of configuration changes and are cleared when activity/fragment is destroyed.

Following is the lifecycle of ViewModel from official site:

ViewModel

Can the viewModel be shared with another Activity ?

You shouldn't do that with Activities. However fragments can share a ViewModel using their activity scope to handle communication between them

How is a ViewModel figuring out internally the right time to call onCleared and finally end its lifecycle?

A VM's onCleared is called when the app is put into the background and the app process is killed in order to free up the system's memory.

See the Do ViewModels persist my data? section from this Android Developer's post, ViewModels: Persistence, onSaveInstanceState(), Restoring UI State and Loaders

If you want the user to be able to put the app into the background and then come back three hours later to the exact same state, you should also persist data. This is because as soon as your activity goes into the background, your app process can be stopped if the device is running low on memory.

If the app process and activity are stopped, then the ViewModel will be cleared as well.

Through the source code, we know the ViewModel binds with HolderFragment. you can from the code in class ViewModelProviders to find it.

@MainThread
public static ViewModelProvider of(@NonNull FragmentActivity activity,
@NonNull Factory factory) {
checkApplication(activity);
return new ViewModelProvider(ViewModelStores.of(activity), factory);
}

next, in-class HolderFragment on it's onDestroy() you can find

@Override
public void onDestroy() {
super.onDestroy();
mViewModelStore.clear();
}

Last, open it,

public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.onCleared();
}
mMap.clear();
}

now, maybe you have know it. just like the picture above. When the fragment finished, it cleared; when activity recreate,the fragment's onDestroy() will not be invoked, because

public HolderFragment() {
setRetainInstance(true);
}

hope it can help you.

Check method onDestroy() in Fragment.java

public void onDestroy() {
this.mCalled = true;
FragmentActivity activity = this.getActivity();
boolean isChangingConfigurations = activity != null && activity.isChangingConfigurations();
if (this.mViewModelStore != null && !isChangingConfigurations) {
this.mViewModelStore.clear();
}
}

The variant isChangingConfigurations is true when the Activity rotates, the viewModelStore method clear() is not called.

When Activity is destroyed, isChangingConfigurations is false, the viewModelStore will be cleared.

If you follow the trail (Check super class) AppCompatActivity --> FragmentActivity --> ComponentActivity

ComponentActivity observe the lifecycle state.

onDestory() calls at configuration change (such as screen rotation) but viewModel doesn't get destroy because of the following condition.

getLifecycle().addObserver(new GenericLifecycleObserver() {
@Override
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
if (event == Lifecycle.Event.ON_DESTROY) {
if (!isChangingConfigurations()) {
getViewModelStore().clear();
}
}
}
});

I wanted my VM's onClear to be called when the Activity was finishing. I use onPause, because the call to onDestroy is not always immediately executed...it could be a few seconds after onPause:

class SomeActivity : AppCompatActivity() {


override fun onPause() {
super.onPause()


// viewmodel is not always cleared immediately after all views detach from it, which delays
// the vm's cleanup code being called, which lets the resources continue running
// after all UIs detach, which is weird, because I was using timers and media players.
// this makes the VM execute onCleared when its Activity detaches from it.
if (isFinishing) {
viewModelStore.clear()
}
}
}

And here is the order of execution in respect to the GenericLifecycleObserver:

  1. onStateChanged()
  2. onResume()/onDestroy()/etc.

Meaning the observer received the information about the pending state change before it's completed, so for exemple onDestroy() method is finished.