/ android

Android ViewModel Arch Component Internals

Keen to check out the new Android arch components, I decided to take some time and poke around the Android ViewModel architecture component after testing it for my side projects, in order to better understand what was happening under the hood. It's pretty cool. Here's a simplified diagram of what I found:

viewmodel1

So essentially, when you create your ViewModel (and your factory if you need one) and bind your viewmodel to your view using the following:

UserViewModel = ViewModelProviders.of(this, viewModelFactory).get(UserViewModel.class);

So The ViewModelProviders class returns an instance of the ViewModel Store - ViewModelStores.class. The ViewModel Store does two things:

  • First, it puts your ViewModel in a hashmap in order to keep a reference to it. Once that reference is no longer needed (it will know this by using the second point below), the ViewModel is cleared from the hashmap:
    private final HashMap<String, ViewModel> mMap = new HashMap<>();

    final void put(String key, ViewModel viewModel) {
        ViewModel oldViewModel = mMap.get(key);
        if (oldViewModel != null) {
            oldViewModel.onCleared();
        }
        mMap.put(key, viewModel);
    }

  • Second - it passes a reference to your fragment/activity to a class called HolderFragmentvia the holderfragmentFor static method within that class.
    @MainThread
    public static ViewModelStore of(@NonNull FragmentActivity activity) {
        return holderFragmentFor(activity).getViewModelStore();
    }

This is actually how it knows what the lifecycle of your Activity/Fragment is, and then destroys it when necessary (either by knowing that the onDestroy method has been called or the app gets killed by Android). Your Fragment/Activity reference is also stored in a hashmap.

//hashamp for the holderfragment manager:

private static final HolderFragmentManager sHolderFragmentManager = new HolderFragmentManager()

//method that gets called when your activity gets destroyed:
        private ActivityLifecycleCallbacks mActivityCallbacks =
                new EmptyActivityLifecycleCallbacks() {
                    @Override
                    public void onActivityDestroyed(Activity activity) {
                        HolderFragment fragment = mNotCommittedActivityHolders.remove(activity);
                        if (fragment != null) {
                            Log.e(LOG_TAG, "Failed to save a ViewModel for " + activity);
                        }
                    }
                };

The HolderFragment class extends the Fragment class which means it has access to the same lifecycle method/callbacks a general activity/fragment has, so the following methods are implemented:

    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        sHolderFragmentManager.holderFragmentCreated(this);
    }

This one checks for any existing parent fragments or activities if any, and removes them from the stack before adding the relevant ones (the one's were using for this instance of our application),

We also have this:

    public HolderFragment() {
        setRetainInstance(true);
    }

This method assist in keeping the configuration of the screen that survived changes such as the screen rotation.

There are a couple of methods that do the management of the holder such as registering for your application lifecycle callbacks then doing the necessary state changes of the viewmodel. One such interesting method is the original holderFragmentFor method mentioned above that shows this in action:

        HolderFragment holderFragmentFor(FragmentActivity activity) {
            FragmentManager fm = activity.getSupportFragmentManager();
            HolderFragment holder = findHolderFragment(fm);
            if (holder != null) {
                return holder; 
            }
            holder = mNotCommittedActivityHolders.get(activity);
            if (holder != null) {
                return holder; 
            }

            if (!mActivityCallbacksIsAdded) {
                mActivityCallbacksIsAdded = true;
     
 //this is where we register for the lifecycle callbacks of our app     activity.getApplication().registerActivityLifecycleCallbacks(mActivityCallbacks); 
            }
            holder = createHolderFragment(fm);
            mNotCommittedActivityHolders.put(activity, holder); 
            //we then add the activity we're tracking the callback for 
            return holder;
        }

So in a nutshell this is how the MVVM components keeps track of your application lifecycle, and destroys the necessary references when necessary. Also this is how your ViewModel can survive configuration changes.

There is quite a bit more left to explore and am still getting to know the architecture components in general but deep diving into how it worked and gaining a fair understanding of what's happening under the hood is always good fun.

If you found this and have learnt something, glad I could help!

Please let me know if there is anything you need me to add in order to make the article (and future ones better) as this is my first post on the internals :) You can get hold of me here

Thanks!

Vusi Moyo

Some guy that found code on the internet and is treating it like play dough

Read More