何时调用 viewmodel onCleared
Posted
技术标签:
【中文标题】何时调用 viewmodel onCleared【英文标题】:When is the viewmodel onCleared called 【发布时间】:2018-12-01 16:24:32 【问题描述】:ViewModel 是独立于活动/片段生命周期还是仅独立于它们的配置更改。它们何时将不复存在并调用后续的 onCleared() 方法。 viewModel 可以与其他 Activity 共享吗?
一种情况:
Activity1+viewModel1--->(rotation)--->Activity1+viewModel1
--->(launch Intent)--->Activity2+viewModel1
这种分享可行吗?这是一种好习惯吗?
此外,由于应用程序生命周期回调,onPause->onStop->onDestroy 对于两者都是相同的
1.activity旋转和
2.当一个Activity结束时,
ViewModel 如何在内部确定调用 onCleared 并最终结束其生命周期的正确时间。
调查结果:
ViewModel 在内部使用 holderFragment 来保存 Activity 的实例,并像片段一样使用 setRetainInstance 方法来说明配置更改。
Source: dive-inside-of-androids-viewmodel-architecture-components
【问题讨论】:
在您的情况下,ViewModel 是什么? developer.android.com/topic/libraries/architecture/viewmodel 【参考方案1】:ViewModel 是独立于活动/片段生命周期还是仅仅 他们的配置更改。
ViewModel (VM) 独立于配置更改,并在销毁活动/片段时被清除。
以下是官网lifecycle of ViewModel:
viewModel 可以与其他 Activity 共享吗?
您不应该对活动这样做。然而,片段可以共享ViewModel
,使用它们的活动范围来处理它们之间的通信
ViewModel 如何在内部确定调用
onCleared
并最终结束其生命周期的正确时间?
当应用程序进入后台并杀死应用程序进程以释放系统内存时,会调用 VM 的 onCleared
。
请参阅此 Android 开发者帖子中的 Do ViewModels persist my data? 部分,ViewModels: Persistence, onSaveInstanceState(), Restoring UI State and Loaders
如果您希望用户能够将应用程序置于后台,然后在三个小时后返回到完全相同的状态,您还应该持久化数据。这是因为一旦您的 Activity 进入后台,如果设备内存不足,您的应用进程就会停止。
如果应用进程和活动停止,则 ViewModel 也将被清除。
【讨论】:
由于应用程序生命周期回调,onPause->onStop->onDestroy 对于旋转和 Activity 结束时都是相同的,ViewModel 如何在内部确定调用 onCleared 并最终结束其生命周期的正确时间. @ir2pid 您可以查看this blog 了解内部实现细节【参考方案2】:在Fragment.java
中检查方法onDestroy()
public void onDestroy()
this.mCalled = true;
FragmentActivity activity = this.getActivity();
boolean isChangingConfigurations = activity != null && activity.isChangingConfigurations();
if (this.mViewModelStore != null && !isChangingConfigurations)
this.mViewModelStore.clear();
当Activity旋转时变体isChangingConfigurations为真,不调用viewModelStore方法clear()。
当Activity被销毁时,isChangingConfigurations为false,viewModelStore会被清空。
【讨论】:
您使用哪个版本的 Fragment 库?在androidx.fragment:fragment:1.2.5
我找不到那个。当然,我找到了方法 onDestroy
但没有 var isChangigConf
等)我猜它隐藏在其他地方。
@VítKapitola:检查ComponentActivity
或FragmentManager
@HuyNguyen 我在ComponentActivity
或FragmentManager
都没有找到它...【参考方案3】:
通过源码我们知道ViewModel绑定了HolderFragment。您可以从 ViewModelProviders 类中的代码中找到它。
@MainThread
public static ViewModelProvider of(@NonNull FragmentActivity activity,
@NonNull Factory factory)
checkApplication(activity);
return new ViewModelProvider(ViewModelStores.of(activity), factory);
接下来,你可以在 onDestroy()
上找到类内的 HolderFragment
@Override
public void onDestroy()
super.onDestroy();
mViewModelStore.clear();
最后,打开它,
public final void clear()
for (ViewModel vm : mMap.values())
vm.onCleared();
mMap.clear();
现在,也许你已经知道了。就像上面的图片一样。当片段完成时,它会清除;当activity重新创建时,fragment的onDestroy()不会被调用,因为
public HolderFragment()
setRetainInstance(true);
希望对你有帮助。
【讨论】:
@IgorGanapolsky 。我的天啊。是Through
还是不是throw
。是我的错……哈哈哈【参考方案4】:
如果你跟随线索(检查超类) AppCompatActivity --> FragmentActivity --> ComponentActivity
ComponentActivity 观察生命周期状态。
onDestory() 在配置更改(例如屏幕旋转)时调用,但由于以下情况,viewModel 不会被销毁。
getLifecycle().addObserver(new GenericLifecycleObserver()
@Override
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event)
if (event == Lifecycle.Event.ON_DESTROY)
if (!isChangingConfigurations())
getViewModelStore().clear();
);
【讨论】:
由于Lifecycle.Event.ON_DESTROY,它确实得到了销毁调用【参考方案5】:我希望在 Activity
完成时调用我的 VM 的 onClear。我使用onPause
,因为对onDestroy
的调用并不总是立即执行......它可能在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()
【讨论】:
如果用户收到一个导致您的活动暂停的对话框,您也将破坏视图模型;这不是禁止的,但如果我在生产代码中看到这一点,我真的会皱眉。 @MartinMarconcini 在这些情况下是isFinishing
吗?我做了一些测试,比如请求权限,并让系统权限对话框出现。在这种情况下,onPause
被调用,但isFinishing
为假,因此不会清除 VM。我也尝试显示DialogFragment
,但在这种情况下不会调用onPause
啊,好点子,老实说我不确定,我必须查看在 ViewModel 上触发 onCleared() 的最新代码,但有这通常发生的两个条件:onDestroy
和 一个名为 isOrientationChange
或类似的布尔值(基本上,如果你“旋转”了你的设备,那么 viewModel 将不会被清除)。我认为您对此很满意,只是在我看来,它以某种方式违背了 viewModels 约定的目的,而我从来没有理由改变它,这就是我皱眉的原因。我并不是在暗示这是不好的或以任何方式被禁止的。我认为你很安全。以上是关于何时调用 viewmodel onCleared的主要内容,如果未能解决你的问题,请参考以下文章
使用 LiveData 和 ViewModel 删除项目会导致重新发射
如何使用 mvvm 模式从不同的 ViewModel 获取属性和调用命令