When is the viewmodel onCleared called

AndroidAndroid ActivityAndroid LifecycleAndroid Viewmodel

Android Problem Overview


Are ViewModels independent of activity/fragment lifecycles or just their configuration changes. When will they cease to exist and the subsequent onCleared() method called. Can the viewModel be shared with another Activity ?

A situation:

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

is this sharing possible and is it a good practice.

Also, since the app lifecycle callbacks, onPause->onStop->onDestroy is same for both

1.activity rotating and

2.when an Activity ends,

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


Findings:

the ViewModel uses a holderFragment internally to hold an instance of the activity and uses the setRetainInstance method like fragments to account for configuration changes.

Source: dive-inside-of-androids-viewmodel-architecture-components

enter image description here

Android Solutions


Solution 1 - Android

> 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.

Solution 2 - Android

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.

Solution 3 - Android

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.

Solution 4 - Android

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

Solution 5 - Android

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionir2pidView Question on Stackoverflow
Solution 1 - AndroidSagarView Answer on Stackoverflow
Solution 2 - AndroidEric YView Answer on Stackoverflow
Solution 3 - AndroidLongaleiView Answer on Stackoverflow
Solution 4 - AndroidsajalView Answer on Stackoverflow
Solution 5 - AndroidEricView Answer on Stackoverflow