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:
-
onDestroy()
is called, and - We are not undergoing a configuration change
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:
- References to threads, Kotlin coroutines, or the like
- Open Internet connections to some server
- Open references to local databases
- And so on
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.