何时调用 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:检查ComponentActivityFragmentManager @HuyNguyen 我在ComponentActivityFragmentManager 都没有找到它...【参考方案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 删除项目会导致重新发射

在 ViewModel 后面的视图代码中调用方法?

如何使用 mvvm 模式从不同的 ViewModel 获取属性和调用命令

从 ViewModel 调用视图中的方法

KnockoutJS,ajax 调用后更新 ViewModel

Android、MVVM:在 ViewModel 中调用 ContentResolver