DEV Community

Cover image for Do not use AndroidViewModel
Denizhan Dalgıç
Denizhan Dalgıç

Posted on

Do not use AndroidViewModel

Browsing the Google developer documentation for Android, I stumbled upon AndroidViewModel class. Although I use view models, I never heard of it.

Looking at the reference, things became even more strange. It has a reference to the Application class. Its description clearly says: 

Application context aware ViewModel

And here is the source code:

/**
 * Application context aware {@link ViewModel}.
 * <p>
 * Subclasses must have a constructor which accepts {@link Application} as the only parameter.
 * <p>
 */
public class AndroidViewModel extends ViewModel {
    @SuppressLint("StaticFieldLeak")
    private Application mApplication;

    public AndroidViewModel(@NonNull Application application) {
        mApplication = application;
    }

    /**
     * Return the application.
     */
    @SuppressWarnings("TypeParameterUnusedInFormals")
    @NonNull
    public <T extends Application> T getApplication() {
        //noinspection unchecked
        return (T) mApplication;
    }
}
Enter fullscreen mode Exit fullscreen mode

Look at this abomination. The constructor needs an instance of Application. The property mApplication even has StaticFieldLeak suppressed.

Like, what? I thought the whole philosophy behind the view models was to isolate business logic from the Android framework.

It's safe to say that the context class is one of the most commonly used classes in the Android world. Junior developers who use view models should avoid making a habit of passing this class around. However, this is not a product of a junior developer. This is an official library.

Image description

In fact, the official recommendations for Android architecture suggest not using AndroidViewModel. It recommends to move the dependency to the UI or the data layer. Exactly. Here are the top reasons why:

  1. Memory leaks
  2. Lack of testability
  3. Coupling

Image description

Context is highly coupled with the Android framework and we should always avoid using any Android-specific classes in our view models.

When you are creating a view model class, the right class to inherit is ViewModel and ViewModel only.

This sparks a question: Why is there an official implementation of such a thing in the first place?

Disclaimer: The cover image is created with AI.

Top comments (4)

Collapse
 
cbeyls profile image
Christophe Beyls

This class exists so you can provide Android dependencies to the abstractions you're using in the ViewModel, without having to rely on a dependency injection framework.
Because like it or not, on Android you always end up needing a Context as dependency as soon as you need to access file paths, resources or services for example.
Passing the Application gives maximum flexibility while guaranteeing that the Context is an Application context and will not leak the Activity.

Collapse
 
devdalgic profile image
Denizhan Dalgıç

I personally don't end up with Context in projects I'm developing.
Device-specific stuff should be passed from classes which already has access to the context. This applies for resources, too. If I really need to decide some resources, I can use resource ids and then get that resource from an Activity.

Collapse
 
cbeyls profile image
Christophe Beyls

It's indeed a good practice to remove Context from all the public APIs of our components, at least to make them easier to test. However, internally at the bottom level, many components in an Android app always end up needing a Context because Android requires it for so many things: accessing a system service, starting a component, connecting to a MediaSession, connecting to the Firebase SDK, ... or just simply accessing the file system!

So let's take an example: you have a ViewModel that needs to call a repository that internally uses a Room database for storage. Room needs a Context to be initialized. If you're not using dependency injection (like many Android apps back in 2017) and you want to lazily initialize this repository the first time you access it, then you'll have no choice but to pass a Context to it. AndroidViewModel was created to provide the application Context for that usage, so you don't have to pass an Activity Context manually from the View layer and risk creating a leak.

Of course today using dependency injection is the recommended way and injecting components with the right Context into a ViewModel constructor is easy with a library like Dagger Hilt.

Thread Thread
 
devdalgic profile image
Denizhan Dalgıç

Now I get what you are saying. You're right, of course. I didn't mean to pass repository to ViewModel. That'd be chaos 😀

The main reason I've written this article is because you don't get any warnings in Android Studio when using AndroidViewModel, even though it is clearly said not to be used in documentation.

Google deprecates functions aggressively, and sometimes to "direct" people to use good practices. However, it seems that this doesn't apply to AndroidViewModel.