Activity Stack Life Cycle (Part 1)
Perhaps the most popular question at interviews with an Android developer is: “tell us about the Activity life cycle.” At first glance, this is nothing complicated, in which only a blog has not yet been written about this, and the candidate immediately begins to draw a well-known block diagram and explain it along the way. The spherical life cycle in a vacuum, with which all lessons abound, is really simple enough to understand, but activity is only part of some kind of generalizing essence. This entity is called Activity Stack, and with its life cycle we will now try to figure it out.
Life Stack Activity Stack (Part 2)
Available:
ActivityA, ActivityB, ActivityC
On the layout of each of their Activities there is one button that makes the usual launch of the next Activity:
That is, ActivityA starts ActivityB, ActivityB starts ActivityC, and ActivityC starts ActiviyA again.
The Activity stack is the stack and that the rule “last come, first go” works for him. Using the back button, the current Activity is destroyed (
For clarity, the log A-> B-> C-> back-> back-> back:
Everyone is familiar with this behavior, but is our Activity Stack protected if we decide to leave the application in the background and run a resource-consuming third-party application?
App1-> A-> B-> C-> Home-> App2-> back-> App1:
From the log, we see that the process of our application (
We’ll do something similar, just don’t wait until a third-party application requires memory and kills our application, but do it yourself through the Application Manager using the Force Stop button.
App1-> A-> B-> C-> Home-> App Manager-> Force Stop-> App1
We get a completely different behavior: the Activity Stack is lost, and when the application starts after the force stop, we find ourselves in the root ActivityA.
We also draw attention to the fact that in both cases, when our process was destroyed in its entirety, no method was called in any Activity
We figured out the default behavior, but there are tools in Android’s arsenal to change the behavior to our needs. We will consider them in the next part.
PS Added your comments to the logs at the request of Vest . Thanks! It seems to have become clearer.
Life Stack Activity Stack (Part 2)
Available:
ActivityA, ActivityB, ActivityC
On the layout of each of their Activities there is one button that makes the usual launch of the next Activity:
Intent intent = new Intent(view.getContext(), ActivityB.class);
startActivity(intent);
That is, ActivityA starts ActivityB, ActivityB starts ActivityC, and ActivityC starts ActiviyA again.
The Activity stack is the stack and that the rule “last come, first go” works for him. Using the back button, the current Activity is destroyed (
onDestroy()
), and the previous one is restored ( onCreate()
and / or onStart()
) if the destroyed one was not root. For clarity, the log A-> B-> C-> back-> back-> back:
*** Стартуем приложение ***
I/ActivityManager(249): START {act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.habrahabr.ActivityStackLifeCycle/.ActivityA u=0} from pid 8672
D/ActivityA(28229): onCreate()
D/ActivityA(28229): onStart()
I/ActivityManager(249): Displayed com.habrahabr.ActivityStackLifeCycle/.ActivityA: +234ms
*** Переход на ActivityB ***
I/ActivityManager(249): START {cmp=com.habrahabr.ActivityStackLifeCycle/.ActivityB u=0} from pid 28229
D/ActivityB(28229): onCreate()
D/ActivityB(28229): onStart()
I/ActivityManager(249): Displayed com.habrahabr.ActivityStackLifeCycle/.ActivityB: +135ms
D/ActivityA(28229): onStop()
*** Переход на ActivityC ***
I/ActivityManager(249): START {cmp=com.habrahabr.ActivityStackLifeCycle/.ActivityC u=0} from pid 28229
D/ActivityC(28229): onCreate()
D/ActivityC(28229): onStart()
I/ActivityManager(249): Displayed com.habrahabr.ActivityStackLifeCycle/.ActivityC: +206ms
D/ActivityB(28229): onStop()
*** Жмём Back ***
D/ActivityB(28229): onStart()
D/ActivityC(28229): onStop()
D/ActivityC(28229): onDestroy()
*** Жмём Back ***
D/ActivityA(28229): onStart()
D/ActivityB(28229): onStop()
D/ActivityB(28229): onDestroy()
*** Жмём Back ***
D/ActivityA(28229): onStop()
D/ActivityA(28229): onDestroy()
Everyone is familiar with this behavior, but is our Activity Stack protected if we decide to leave the application in the background and run a resource-consuming third-party application?
App1-> A-> B-> C-> Home-> App2-> back-> App1:
*** Стартуем приложение ***
I/ActivityManager(249): START {flg=0x10000000 cmp=com.habrahabr.ActivityStackLifeCycle/.ActivityA u=0} from pid 1195
I/ActivityManager(249): Start proc com.habrahabr.ActivityStackLifeCycle for activity com.habrahabr.ActivityStackLifeCycle/.ActivityA: pid=1267 uid=10060 gids={1028}
D/ActivityA(1267): onCreate()
D/ActivityA(1267): onStart()
*** Жмём Home, запускаем ресурсо-затратное приложение, балуемся, ждём, пока процесс нашего приложения умрёт ***
<...>
I/ActivityManager(249): Process com.habrahabr.ActivityStackLifeCycle (pid 1267) has died.
<...>
*** Выходим из стороннего приложения, запускаем наше приложение снова ***
I/ActivityManager(249): Start proc com.habrahabr.ActivityStackLifeCycle for activity com.habrahabr.ActivityStackLifeCycle/.ActivityC: pid=1879 uid=10060 gids={1028}
D/ActivityC(1879): onCreate()
D/ActivityC(1879): onStart()
From the log, we see that the process of our application (
id=1267
) was killed, but this did not stop Android from returning to our application to create a new one ( id=1879
) and open the last ActivityC that we were on when we minimized the application. We’ll do something similar, just don’t wait until a third-party application requires memory and kills our application, but do it yourself through the Application Manager using the Force Stop button.
App1-> A-> B-> C-> Home-> App Manager-> Force Stop-> App1
*** Стартуем приложение ***
I/ActivityManager(249): START {flg=0x10000000 cmp=com.habrahabr.ActivityStackLifeCycle/.ActivityA u=0} from pid 32050
I/ActivityManager(249): Start proc com.habrahabr.ActivityStackLifeCycle for activity com.habrahabr.ActivityStackLifeCycle/.ActivityA: pid=32090 uid=10060 gids={1028}
D/ActivityA(32090): onCreate()
D/ActivityA(32090): onStart()
<...>
*** Жмём Home, запускаем Application Manager, находим наше приложение и делаем ему Force Stop ***
I/ActivityManager(249): Force stopping package com.habrahabr.ActivityStackLifeCycle uid=10060
I/ActivityManager(249): Killing proc 32090:com.habrahabr.ActivityStackLifeCycle/u0a60: force stop
I/ActivityManager(249): Force finishing activity ActivityRecord{419ba4b0 com.habrahabr.ActivityStackLifeCycle/.ActivityA}
I/ActivityManager(249): Force finishing activity ActivityRecord{41c392b8 com.habrahabr.ActivityStackLifeCycle/.ActivityB}
I/ActivityManager(249): Force finishing activity ActivityRecord{41ac4588 com.habrahabr.ActivityStackLifeCycle/.ActivityC}
<...>
*** Выходим из Application Manager, запускаем наше приложение снова ***
I/ActivityManager(249): START {flg=0x10104000 cmp=com.habrahabr.ActivityStackLifeCycle/.ActivityA u=0} from pid 337
I/ActivityManager(249): Start proc com.habrahabr.ActivityStackLifeCycle for activity com.habrahabr.ActivityStackLifeCycle/.ActivityA: pid=32378 uid=10060 gids={1028}
D/ActivityA(32378): onCreate()
D/ActivityA(32378): onStart()
We get a completely different behavior: the Activity Stack is lost, and when the application starts after the force stop, we find ourselves in the root ActivityA.
We also draw attention to the fact that in both cases, when our process was destroyed in its entirety, no method was called in any Activity
onDestroy()
, this is undoubtedly worth considering when developing. We figured out the default behavior, but there are tools in Android’s arsenal to change the behavior to our needs. We will consider them in the next part.
PS Added your comments to the logs at the request of Vest . Thanks! It seems to have become clearer.