ViewModel and the Lifecycle

Our MainActivity also has calls to Log.d() in the main lifecycle functions, both in Java:

package com.commonsware.jetpack.samplerj.viewmodel;

import android.os.Bundle;
import android.util.Log;
import com.commonsware.jetpack.samplerj.viewmodel.databinding.ActivityMainBinding;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;

public class MainActivity extends AppCompatActivity {
  private static final String TAG = "ViewModel";

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    final ActivityMainBinding binding =
      ActivityMainBinding.inflate(getLayoutInflater());

    setContentView(binding.getRoot());

    ColorAdapter adapter = new ColorAdapter(getLayoutInflater());
    ColorViewModel vm = new ViewModelProvider(this).get(ColorViewModel.class);

    adapter.submitList(vm.numbers);
    binding.items.setLayoutManager(new LinearLayoutManager(this));
    binding.items.addItemDecoration(
      new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
    binding.items.setAdapter(adapter);

    Log.d(TAG, "onCreate() called!");
  }

  @Override
  protected void onStart() {
    super.onStart();

    Log.d(TAG, "onStart() called!");
  }

  @Override
  protected void onResume() {
    super.onResume();

    Log.d(TAG, "onResume() called!");
  }

  @Override
  protected void onPause() {
    Log.d(TAG, "onPause() called!");

    super.onPause();
  }

  @Override
  protected void onStop() {
    Log.d(TAG, "onStop() called!");

    super.onStop();
  }

  @Override
  protected void onDestroy() {
    Log.d(TAG, "onDestroy() called!");

    super.onDestroy();
  }
}

…and in Kotlin:

package com.commonsware.jetpack.sampler.viewmodel

import android.os.Bundle
import android.util.Log
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import com.commonsware.jetpack.sampler.viewmodel.databinding.ActivityMainBinding

private const val TAG = "ViewModel"

class MainActivity : AppCompatActivity() {
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    val binding = ActivityMainBinding.inflate(layoutInflater)

    setContentView(binding.root)

    val vm: ColorViewModel by viewModels()

    binding.items.apply {
      layoutManager = LinearLayoutManager(this@MainActivity)
      addItemDecoration(
        DividerItemDecoration(
          this@MainActivity,
          DividerItemDecoration.VERTICAL
        )
      )
      adapter = ColorAdapter(layoutInflater).apply {
        submitList(vm.numbers)
      }
    }

    Log.d(TAG, "onCreate() called!")
  }

  override fun onStart() {
    super.onStart()

    Log.d(TAG, "onStart() called!")
  }

  override fun onResume() {
    super.onResume()

    Log.d(TAG, "onResume() called!")
  }

  override fun onPause() {
    Log.d(TAG, "onPause() called!")

    super.onPause()
  }

  override fun onStop() {
    Log.d(TAG, "onStop() called!")

    super.onStop()
  }

  override fun onDestroy() {
    Log.d(TAG, "onDestroy() called!")

    super.onDestroy()
  }
}

As you run the app, and as you undergo configuration changes, you will see the lifecycle methods get logged, by looking for these messages in the Logcat view in Android Studio. For example, starting the app will result in Logcat messages like:

com.commonsware.jetpack.sampler.viewmodel D/ViewModel: onCreate() called!
com.commonsware.jetpack.sampler.viewmodel D/ViewModel: onStart() called!
com.commonsware.jetpack.sampler.viewmodel D/ViewModel: onResume() called!

If you rotate the screen, the list of messages becomes:

com.commonsware.jetpack.sampler.viewmodel D/ViewModel: onCreate() called!
com.commonsware.jetpack.sampler.viewmodel D/ViewModel: onStart() called!
com.commonsware.jetpack.sampler.viewmodel D/ViewModel: onResume() called!
com.commonsware.jetpack.sampler.viewmodel D/ViewModel: onPause() called!
com.commonsware.jetpack.sampler.viewmodel D/ViewModel: onStop() called!
com.commonsware.jetpack.sampler.viewmodel D/ViewModel: onDestroy() called!
com.commonsware.jetpack.sampler.viewmodel D/ViewModel: onCreate() called!
com.commonsware.jetpack.sampler.viewmodel D/ViewModel: onStart() called!
com.commonsware.jetpack.sampler.viewmodel D/ViewModel: onResume() called!

If you press BACK to exit the rotated activity, the list of messages becomes:

com.commonsware.jetpack.sampler.viewmodel D/ViewModel: onCreate() called!
com.commonsware.jetpack.sampler.viewmodel D/ViewModel: onStart() called!
com.commonsware.jetpack.sampler.viewmodel D/ViewModel: onResume() called!
com.commonsware.jetpack.sampler.viewmodel D/ViewModel: onPause() called!
com.commonsware.jetpack.sampler.viewmodel D/ViewModel: onStop() called!
com.commonsware.jetpack.sampler.viewmodel D/ViewModel: onDestroy() called!
com.commonsware.jetpack.sampler.viewmodel D/ViewModel: onCreate() called!
com.commonsware.jetpack.sampler.viewmodel D/ViewModel: onStart() called!
com.commonsware.jetpack.sampler.viewmodel D/ViewModel: onResume() called!
com.commonsware.jetpack.sampler.viewmodel D/ViewModel: onPause() called!
com.commonsware.jetpack.sampler.viewmodel D/ViewModel: onStop() called!
com.commonsware.jetpack.sampler.viewmodel D/ViewModel: onDestroy() called!

We are seeing our original activity instance come onto the screen, then get destroyed and a replacement created, before it too gets destroyed as the user exits the activity.

Our ColorViewModel is oblivious to most of this. It will get created as part of the original onCreate() call. When the new activity instance is in its onCreate(), and it attempts to retrieve the ColorViewModel, Jetpack realizes that we already have a ColorViewModel from the previous activity instance, so it reuses it.

If we wanted, we could override onCleared() in ColorViewModel. This will be called when our activity is “really” destroyed:

In onCleared(), we could clean up anything that we needed to clean up. Often, there is nothing that you need to clean up specifically — after all, the ViewModel will get garbage-collected shortly. However, sometimes your ViewModel might hold onto things that should get cleaned up, such as:

To the extent that your ViewModel has those, onCleared() is where you would release those things, such as disconnecting from the server.


Prev Table of Contents Next

This book is licensed under the Creative Commons Attribution-ShareAlike 4.0 International license.