Mobile Development 21 min read

Understanding Android Jetpack ViewModel: Concepts, Usage, and Source Code Analysis

This article explains the purpose and characteristics of Android Jetpack's ViewModel component, demonstrates how to use it with LiveData in Activities and Fragments, shows code examples for data sharing between fragments, and provides an in‑depth analysis of its internal source code and lifecycle handling.

Sohu Tech Products
Sohu Tech Products
Sohu Tech Products
Understanding Android Jetpack ViewModel: Concepts, Usage, and Source Code Analysis

1. Introduction to ViewModel

ViewModel is an important component of Jetpack AAC that serves as a model preparing data for the UI. It stores and manages UI‑related data in a lifecycle‑aware way, allowing data to survive configuration changes such as screen rotation.

Note: This ViewModel is unrelated to the VM concept in MVVM architecture; a separate article will cover MVVM.

1.1 Background

When an Activity is destroyed and recreated (e.g., due to rotation), all UI‑related data stored in the Activity is lost, leading to resource waste if the data must be fetched again. The onSaveInstanceState() method can only store a small amount of serializable data (≈1 MB) and is unsuitable for large objects such as user lists or bitmaps.

UI layers often perform asynchronous requests via a presenter (MVP). Holding a reference to the UI context can cause memory leaks if the request outlives the UI component, requiring extensive cleanup work.

ViewModel addresses both problems by acting as a replacement for the presenter, providing data to the UI without holding UI references.

1.2 Characteristics

1.2.1 Lifecycle longer than Activity

The most important feature is that a ViewModel lives longer than its Activity. After a configuration change, the ViewModel instance is retained while the Activity is recreated. It is cleared only when the Activity finishes permanently.

1.2.2 No UI reference

Because ViewModel does not hold UI references, it cannot cause memory leaks. Data is delivered to the UI through LiveData, which follows an observer pattern.

2. Using ViewModel

2.1 Basic usage

Steps to use ViewModel with LiveData:

Create a custom ViewModel class that extends ViewModel .

Implement UI‑data logic inside the ViewModel.

Expose the data via LiveData .

Obtain the ViewModel instance in an Activity/Fragment using ViewModelProvider .

Observe the LiveData and update the UI accordingly.

Example code for a simple user‑info ViewModel:

public class UserViewModel extends ViewModel {
    private MutableLiveData
userLiveData;
    private MutableLiveData
loadingLiveData;

    public UserViewModel() {
        userLiveData = new MutableLiveData<>();
        loadingLiveData = new MutableLiveData<>();
    }

    // Simulate a network request that returns user info after 2 seconds
    public void getUserInfo() {
        loadingLiveData.setValue(true);
        new AsyncTask
() {
            @Override
            protected void onPostExecute(String s) {
                loadingLiveData.setValue(false);
                userLiveData.setValue(s); // emit user info
            }
            @Override
            protected String doInBackground(Void... voids) {
                try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); }
                String userName = "I am Hu Feiyang, welcome to follow my public account~";
                return userName;
            }
        }.execute();
    }

    public LiveData
getUserLiveData() { return userLiveData; }
    public LiveData
getLoadingLiveData() { return loadingLiveData; }
}

Activity code that consumes the ViewModel:

public class UserActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // ... UI initialization ...
        TextView tvUserName = findViewById(R.id.textView);
        ProgressBar pbLoading = findViewById(R.id.pb_loading);
        ViewModelProvider viewModelProvider = new ViewModelProvider(this);
        UserViewModel userViewModel = viewModelProvider.get(UserViewModel.class);
        // Observe user info
        userViewModel.getUserLiveData().observe(this, s -> tvUserName.setText(s));
        // Observe loading state
        userViewModel.getLoadingLiveData().observe(this, aBoolean -> pbLoading.setVisibility(aBoolean ? View.VISIBLE : View.GONE));
        // Trigger request on button click
        findViewById(R.id.button).setOnClickListener(v -> userViewModel.getUserInfo());
    }
    @Override
    protected void onStop() { super.onStop(); Log.i(TAG, "onStop: "); }
    @Override
    protected void onDestroy() { super.onDestroy(); Log.i(TAG, "onDestroy: "); }
}

When the button is pressed, a progress bar appears, the simulated request finishes after 2 seconds, and the user name is displayed. Rotating the device recreates the Activity, but the data remains because the ViewModel instance is retained.

2.2 Sharing data between Fragments

Multiple fragments within the same Activity can share a ViewModel scoped to the Activity. The ListFragment updates a MutableLiveData in the shared ViewModel, and the DetailFragment observes that LiveData to display the selected item.

public class SharedViewModel extends ViewModel {
    private final MutableLiveData
selected = new MutableLiveData<>();
    public void select(UserContent.UserItem user) { selected.setValue(user); }
    public LiveData
getSelected() { return selected; }
}

// ListFragment
public class MyListFragment extends Fragment {
    private SharedViewModel model;
    @Override
    public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        model = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
        adapter.setListener(userItem -> model.select(userItem));
    }
}

// DetailFragment
public class DetailFragment extends Fragment {
    @Override
    public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        TextView detail = view.findViewById(R.id.tv_detail);
        SharedViewModel model = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
        model.getSelected().observe(getViewLifecycleOwner(), userItem -> detail.setText(userItem.toString()));
    }
}

This approach decouples fragments, requires no direct communication, and survives fragment replacement or removal.

3. Source Code Analysis

The persistence of ViewModel across configuration changes is achieved by storing it in a ViewModelStore that survives Activity recreation.

3.1 ViewModel storage and retrieval

ViewModel is an abstract class with a clear() method that triggers onCleared() when the ViewModel is removed. Instances are created by a Factory (default is NewInstanceFactory ) which uses reflection to call the no‑arg constructor.

3.2 ViewModelStore lifecycle

Activities and Fragments implement ViewModelStoreOwner . In ComponentActivity.getViewModelStore() , the store is first retrieved from the last non‑configuration instance (a holder that survives configuration changes). If none exists, a new ViewModelStore is created.

During a configuration change, Activity.onRetainNonConfigurationInstance() saves the current ViewModelStore into a NonConfigurationInstances object. When the new Activity instance is attached, it receives this object via getLastNonConfigurationInstance() , thus reusing the same store and keeping existing ViewModel objects alive.

4. Comparison with onSaveInstanceState()

4.1 Use cases

onSaveInstanceState() is invoked whenever the system may destroy an Activity (e.g., home button, background, launching another Activity, or rotation). It provides a chance to persist small, serializable data.

ViewModel persistence works only for configuration‑change‑driven recreation, not for arbitrary process death.

4.2 Storage method

ViewModel keeps data in memory, offering fast read/write. onSaveInstanceState() serializes data to a Bundle, which is written to disk.

4.3 Data size limits

ViewModel can hold any amount of data limited only by the app's memory. onSaveInstanceState() is limited to roughly 1 MB and requires objects to be Parcelable/Serializable.

5. Summary

The article introduced ViewModel as a UI‑data model, highlighted its lifecycle‑aware characteristics, demonstrated basic usage with LiveData, showed how to share data between fragments, and performed a detailed source‑code analysis explaining why ViewModel survives configuration changes. It also compared ViewModel with onSaveInstanceState() and set the stage for upcoming MVVM architecture coverage.

mobile developmentarchitectureViewModelAndroidLiveDataJetpack
Sohu Tech Products
Written by

Sohu Tech Products

A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.