Understanding Configuration Changes and ViewModel in Android

Understanding Configuration Changes and ViewModel in Android

1. What Are Configuration Changes?

Configuration changes occur when the device environment changes in a way that affects the UI. Common configuration changes in Android include:

  • Screen Rotation: Switching between portrait and landscape mode.
  • Locale Change: Changing the device language.
  • Night Mode: Switching between light and dark themes.
  • Screen Size Change: Connecting to an external display or resizing the app window.

When a configuration change occurs, Android:

  1. Destroys the current Activity instance.
  2. Recreates a new instance to adapt to the updated configuration (e.g., landscape layout).

This destruction and recreation wipe out any in-memory data Activity by default, which is why data resets with configuration changes unless managed properly.


2. The Role of ViewModel in Managing Data

The ViewModel component in Android Architecture Components is designed to persist data across configuration changes. Unlike an Activity or Fragment, a ViewModel survives the recreation of the UI, allowing data to be retained across these changes.

How ViewModel Works

  1. ViewModelStore: Each Activity has a ViewModelStore that stores all ViewModel instances associated with it.
  2. ViewModelProvider: When the Activity is recreated, ViewModelProvider checks the ViewModelStore for an existing ViewModel instance. If it finds one, it reuses the existing ViewModel.If not, it creates a new ViewModel and stores it in the ViewModelStore.

Benefits of ViewModel

  • Data Persistence: Retains data across configuration changes without additional code.
  • Separation of Concerns: Keeps the UI layer free of data-handling code, which improves readability and maintainability.


3. Example: A Counter App Using ViewModel

Let’s create a simple counter app to demonstrate how ViewModel retains data across configuration changes.

Step 1: Create a ViewModel to Hold Data

class CounterViewModel : ViewModel() {
    private var _counter = MutableLiveData(0)
    val counter: LiveData<Int> get() = _counter

    fun incrementCounter() {
        _counter.value = (_counter.value ?: 0) + 1
    }
}        

Step 2: Set up ViewModel in an Activity

class CounterActivity : AppCompatActivity() {
    private lateinit var viewModel: CounterViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_counter)

        // Obtain ViewModel instance
        viewModel = ViewModelProvider(this).get(CounterViewModel::class.java)

        // Observe counter data and update the UI
        viewModel.counter.observe(this) { count ->
            counterTextView.text = count.toString()
        }

        // Increment counter on button click
        incrementButton.setOnClickListener {
            viewModel.incrementCounter()
        }
    }
}        

In this example:

  • CounterViewModel holds the counter data.
  • When incrementCounter is called, the counter value is updated in the ViewModel.
  • Upon screen rotation, CounterActivity is recreated, but CounterViewModel persists, retaining the counter value.


4. ViewModelProvider and ViewModelProvider.Factory

ViewModelProvider

The ViewModelProvider is responsible for creating and retrieving ViewModel instances. When ViewModelProvider is used:

  1. It first checks if an existing ViewModel is stored in the ViewModelStore.
  2. If found, it reuses that ViewModel instead of creating a new one.
  3. If no ViewModel is found, it creates a new instance and stores it.

ViewModelProvider.Factory

If a ViewModel requires dependencies, such as a repository, ViewModelProvider.Factory can be used to handle this dependency injection.

Example with Factory Pattern

class CounterViewModelFactory(private val repository: CounterRepository) : ViewModelProvider.Factory {
    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        if (modelClass.isAssignableFrom(CounterViewModel::class.java)) {
            return CounterViewModel(repository) as T
        }
        throw IllegalArgumentException("Unknown ViewModel class")
    }
}        

Usage in Activity

class CounterActivity : AppCompatActivity() {
    private lateinit var viewModel: CounterViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_counter)

        val repository = CounterRepository()
        val factory = CounterViewModelFactory(repository)
        viewModel = ViewModelProvider(this, factory).get(CounterViewModel::class.java)

        // Observe counter data and update the UI
        viewModel.counter.observe(this) { count ->
            counterTextView.text = count.toString()
        }

        // Increment counter on button click
        incrementButton.setOnClickListener {
            viewModel.incrementCounter()
        }
    }
}        

With this approach, you can pass in dependencies when creating the ViewModel, ensuring it has the resources it needs.


5. How ViewModel Works Behind the Scenes

  1. Activity’s Unique ID: Each Activity has a unique identifier linked to a ViewModelStore.
  2. ViewModelStore: Android assigns a ViewModelStore to the Activity’s ID, acting as a container for all ViewModel instances associated with that Activity.
  3. ViewModel Retention: When a configuration change occurs, the ViewModelStore survives, holding onto the ViewModel instances.
  4. ViewModelProvider: The new Activity instance uses ViewModelProvider to check the ViewModelStore for an existing ViewModel.
  5. Reusing or Creating ViewModel: If an existing ViewModel is found, it is reused. Otherwise, a new one is created and stored.

6.Lifecycle Management

  • Configuration Change: During a configuration change, ViewModel persists since it’s linked to the ViewModelStore, not directly to the Activity lifecycle.
  • Permanent Destruction: When an Activity is permanently destroyed (e.g., the app is closed), the ViewModelStore clears, allowing the ViewModel to be garbage-collected.


Summary

  • Configuration Changes recreate the Activity or Fragment, clearing in-memory data.
  • ViewModel allows data to persist across configuration changes by storing data outside of the Activity lifecycle.
  • ViewModelProvider retrieves the ViewModel from the ViewModelStore, ensuring data is retained across recreations.
  • ViewModelProvider.Factory injects dependencies into the ViewModel when needed.

Using ViewModel ensures that your app’s data persists across configuration changes, improving the user experience by eliminating data loss and making your app more resilient to environmental changes.

要查看或添加评论,请登录

Abdelrhman Ghanem的更多文章

  • Content Providers in Android

    Content Providers in Android

    What Is a Content Provider? A Content Provider acts as an interface for applications to access and modify data from…

  • Understanding URIs in Android

    Understanding URIs in Android

    A Uniform Resource Identifier (URI) is a string of characters uniquely identifying a resource. In Android, URIs are…

  • WorkManager in Android

    WorkManager in Android

    What is WorkManager? WorkManager is an API Android Jetpack provides for scheduling deferrable, asynchronous tasks that…

  • Foreground Services in Android

    Foreground Services in Android

    A Foreground Service is an Android service that performs a task while actively notifying the user, generally through a…

  • Broadcasts and Broadcast Receivers in Android

    Broadcasts and Broadcast Receivers in Android

    Broadcasts in Android allow applications and the Android system to send messages across apps and system components…

  • Intents and Intent Filters in Android

    Intents and Intent Filters in Android

    What is an Intent? An in Android is a messaging object used to request actions from other components like activities…

  • Android Resources and Qualifiers

    Android Resources and Qualifiers

    When building an Android app, you want it to look and work well across all devices. To do that, Android gives us…

  • Context in Android

    Context in Android

    What is Context? In Android, represents the current state of the application. It provides access to various resources…

  • Android Back Stack, Tasks, and Launch Modes

    Android Back Stack, Tasks, and Launch Modes

    In Android, managing screen navigation and app flows effectively depends on understanding the backstack, tasks, and…

  • Android Activity & Fragment Lifecycle

    Android Activity & Fragment Lifecycle

    In Android development, Activities and Fragments are essential components that help create engaging user interfaces…

社区洞察

其他会员也浏览了