The app has 2 screens (First Display and Second Display) carried out utilizing easy compose navigation.
Navigating between screens has no affect on the exercise life cycles. Nonetheless, it could affect View Mannequin lifecycle rely upon the place you instantiate the ViewModel
.
Let’s first have a look at exercise lifecycle first.
Implement DefaultLifecycleObserver
That is the official exercise lifecycle diagram, indicating when these lifecycle occasion callbacks are known as. For instance, earlier than exercise goes into CREATED state, onCreate()
occasion callback known as. This is applicable to the remainder of the lifecycle states.
Please be aware that
onCreate()
and the remainder are lifecycle occasions and never lifecycle states.
To be able to exhibit the exercise lifecycle, it is advisable to implement DefaultLifecycleObserver
interface. Then, you override all of the capabilities and print out the completely different lifecycle states.
class MyLifeCycleObserver(personal val identify: String) : DefaultLifecycleObserver {
personal val tag = "LifeCycleDebug"
override enjoyable onCreate(proprietor: LifecycleOwner) {
Log.d(tag, "$identify: onCreate()")
}
override enjoyable onStart(proprietor: LifecycleOwner) {
Log.d(tag, "$identify: onStart()")
}
override enjoyable onResume(proprietor: LifecycleOwner) {
Log.d(tag, "$identify: onResume()")
}
override enjoyable onPause(proprietor: LifecycleOwner) {
Log.d(tag, "$identify: onPause()")
}
override enjoyable onStop(proprietor: LifecycleOwner) {
Log.d(tag, "$identify: onStop()")
}
override enjoyable onDestroy(proprietor: LifecycleOwner) {
Log.d(tag, "$identify: onDestroy()")
}
}
In exercise, you register this lifecycle observer in onCreate()
perform.
class MainActivity : ComponentActivity() {
override enjoyable onCreate(savedInstanceState: Bundle?) {
tremendous.onCreate(savedInstanceState)
val observer = MyLifeCycleObserver(MainActivity::class.simpleName!!)
lifecycle.addObserver(observer)
}
}
}
For some causes, the onRestart()
callback just isn’t out there in DefaultLifecycleObserver
. So it is advisable to additionally override the onRestart()
in your exercise.
class MainActivity : ComponentActivity() {
override enjoyable onRestart() {
tremendous.onRestart()
Log.d(
"LifeCycleDebug",
"${MainActivity::class.simpleName!!}: onRestart()")
}
}
Simulate Exercise Loses Focus
To be able to exhibit the present exercise lifecycle is paused (loses focus), the present exercise wants to enter background, however nonetheless seen. To do this, you begin a second exercise with clear background.
First, you create this Loses Focus button to start out the second exercise.
val context = LocalContext.present
DefaultButton(
textual content = "Loses Focus",
onClick = {
context.startActivity(Intent(context, SecondActivity::class.java))
}
)
In AndroidManifest.xml
, add the second exercise with android:theme="@android:type/Theme.Translucent"
:
<exercise
android:identify="com.instance.understandlifecyclesdemo.ui.SecondActivity"
android:exported="true"
android:theme="@android:type/Theme.Translucent">
</exercise>
When the button is clicked, the present exercise loses focus. Thus, it goes into PAUSED state.
Exercise Lifecycle Abstract
Attempt to mess around with completely different eventualities and examine the output from Logcat.
Right here is the abstract of all of the completely different eventualities.
State of affairs | Exercise Lifecycle Occasion Callbacks |
Begins up | onCreate() → onStart() → onResume() |
Navigate to completely different screens | No transition |
Begins second clear exercise | onPause() |
Press again button (from the clear exercise) | onResume() |
Rotate display | onPause() → onStop() → onDestroy() → onCreate() → onStart() → onResume() |
Press dwelling button | onPause() → onStop() |
Press sq. button and choose the app | onRestart() → onStart() → onResume() |
Shut down (press again button) | onPause() → onStop() → onDestroy() |
Simulate course of demise (press dwelling button, kill the method manually) | onPause() → onStop() |
Please be aware that in course of demise, onDestroy() occasion callback just isn’t fired.
To simulate course of demise, you first must press the house button to maneuver the exercise into background. After that, you kill the method manually. The best option to kill the method is utilizing the cease button in Logcat.
[Updated – Oct 15, 2022]: The above technique does NOT work anymore on Android Studio Dolphin model. See the next article for extra particulars.
Extra detailed descriptions on every lifecycle state under:
Exercise Lifecycle State | Description |
CREATED | Exercise is created and NOT seen |
STARTED | Exercise is seen at background |
RESUMED | Exercise is seen at foreground |
DESTROYED | Exercise is exited / shut down by person |
Please be aware that there aren’t any
Paused
,Stopped
andRestarted
lifecycle states which I discover it a bit complicated. See diagram under.
ON_PAUSE occasion sends the lifecyle state to STARTED. ON_STOP occasion sends the lifecyle state to CREATED.
Lifecycle Occasion | Lifecycle State | Description |
ON_PAUSE | STARTED | Exercise is paused and visual, nonetheless in foreground |
ON_STOP | CREATED | Exercise is NOT seen, transfer from foreground to background |
N/A | RESTARTED | Intermediate state between Stopped and Began phases |
For full documentation, you possibly can confer with this official documentation right here.
Now, let’s take a look at the View Mannequin lifecycle.
When ViewModel is Created and Destroyed?
There are solely 2 lifecycle phases in View Mannequin:
ViewModel
is created. That’s whenViewModel
constructor known as.ViewModel
is destroyed. That’s whenViewModel.onCleared()
known as.
class MainViewModel(personal val identify: String) : ViewModel() {
personal val tag = "LifeCycleDebug"
init {
Log.d(tag, "${identify}ViewModel: onCreated()")
}
override enjoyable onCleared() {
tremendous.onCleared()
Log.d(tag, "${identify}ViewModel: onCleared()")
}
}
Since MainViewModel
takes in constructor parameter (to distinguish the ViewModel
situations), it is advisable to create the MainViewModelFactory
class MainViewModelFactory(personal val identify: String)
: ViewModelProvider.NewInstanceFactory() {
override enjoyable <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(MainViewModel::class.java))
return MainViewModel(identify) as T
throw IllegalArgumentException("Unknown ViewModel class")
}
}
To be able to exhibit this View Mannequin lifecycle, you create the ViewModel
in 3 completely different locations:
Create ViewModel in MainScreen()
@Composable
personal enjoyable MainScreen() {
val viewModel: MainViewModel = viewModel(
manufacturing facility = MainViewModelFactory("MainScreen"))
}
Create ViewModel in FirstScreen()
@Composable
enjoyable FirstScreen(
navigateToSecondScreen: () -> Unit
) {
val viewModel: MainViewModel = viewModel(
manufacturing facility = MainViewModelFactory("FirstScreen"))
}
Create ViewModel in SecondScreen()
@Composable
enjoyable SecondScreen(
popBackStack: () -> Unit,
) {
val viewModel: MainViewModel = viewModel(
manufacturing facility = MainViewModelFactory("SecondScreen"))
}
View Mannequin Lifecycle Abstract
Let’s examine the Logcat and see what occurs.
State of affairs | View Mannequin Lifecycle State |
Begins up | After exercise is resumed, important and first display view fashions are created |
Navigate to Second Display | Second display view mannequin is created |
Pop again to first Display | Second display view mannequin is destroyed |
Rotate the display | No affect to view mannequin lifecycle |
Press again and exit the app | After exercise is destroyed, important and first display view fashions are destroyed |
ViewModelStoreOwner
determines the view mannequin lifecycle. It’s set to LocalViewModelStoreOwner.present
depends upon the place you name the viewModel()
composable perform.
In MainScreen()
, earlier than the navigation graph is construct, the ViewModelStoreOwner
belongs to the exercise. In FirstScreen()
and SecondScreen()
, compose navigation creates a brand new ViewModelStoreOwner
for every display vacation spot. Nonetheless, since First Display is the foundation/begin vacation spot, its lifecycle very a lot the identical because the Essential Display view mannequin, which is tied to the exercise lifecycle.
So, after the exercise is resumed, each Essential and First Display view fashions are created. Second Display view mannequin is created when it’s pushed to the stack. When it pops from stack, it’s then destroyed.
When the app is shutdown, exercise is destroyed. After that, Essential and First Display view fashions are destroyed. The diagram under summarizes what occurs.
Conclusion
Exercise lifecycle is widespread and effectively documented. Nonetheless, it isn’t utterly clear on view mannequin lifecycle, particularly when it will likely be destroyed.
Earlier than I ran the check on this straightforward app, I had an impression that when the composable display is gone off-screen, its view mannequin is destroyed. I assumed the view mannequin lifecycle is tied to composable display.
Properly, this isn’t the case. It’s based mostly on the again stack from the navigation. When the display is added into the again stack, its view mannequin is created. When it’s faraway from the again stack, its view mannequin is destroyed.
Supply Code
GitHub Repository: Demo_UnderstandLifecycles