Activities in the Wild: Exploring the Activity Lifecycle (360|AnDev, July 2016)

Activities in the Wild: Exploring the Activity Lifecycle (360|AnDev, July 2016)

[Check out the video of this presentation from 360AnDev 2016: https://realm.io/news/activities-in-the-wild-exploring-the-activity-lifecycle-android/]

Running, or paused, or stopped, or destroyed? Oh my! As Android developers we have little control over what state our activities are in. But we do have the ability to hook into transitions between these states to respond appropriately and ensure a pleasant user experience.

Through concrete examples you will learn how the creation and destruction of your activity instances relate to what the user is doing, as well as to what the system is doing. We will explore how state is persisted (or not) in these various scenarios and also explore some little known facts about what happens to your activity in low memory situations.

Finally, we will discuss how knowing when these transitions happen has helped me deal with tricky situations, like continuing video playback while the user interacts with a full-screen overlay.

0f97fa53edac850ba4c64c2df5bd9fb1?s=128

Kristin Marsicano

July 28, 2016
Tweet

Transcript

  1. Activities in the Wild Exploring the Activity Lifecycle Kristin Marsicano

    @kristinmars Big Nerd Ranch
  2. Expectation setting Hello, World!

  3. Demo: Ticker Tally Photo Credit: https://www.amazon.com/GOGO-Counter-Carnival-Manual-Mechanical/dp/B001KX1VW2

  4. Goal for Today Empower you to reason about the Activity

    lifecycle so you can provide a smooth user experience
  5. What is the Activity Lifecycle?

  6. Activity public class TickerActivity extends AppCompatActivity { private int mCount

    = 0;
 ...
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_ticker);
 setupUI();
 updateUI();
 }
 
 ... }
 TickerActivity.java: <?xml version="1.0" encoding="utf-8"?>
 <LinearLayout ...>
 
 <TextView ... />
 
 <TextView ... />
 
 <Button … />
 
 </LinearLayout>
 activity_ticker.xml:
  7. Activity Manager

  8. Activity Manager User clicks Ticker icon on Launch Screen

  9. Activity Manager User clicks Ticker icon on Launch Screen

  10. Activity Manager User clicks Ticker icon on Launch Screen Intent:

    TickerActivity
  11. Activity Manager Activity Manager User clicks Ticker icon on Launch

    Screen Intent: TickerActivity
  12. Activity Manager Activity Manager User clicks Ticker icon on Launch

    Screen Intent: TickerActivity
  13. Activity Manager Activity Manager User clicks Ticker icon on Launch

    Screen Intent: TickerActivity Spin up app process
  14. Activity Manager Activity Manager User clicks Ticker icon on Launch

    Screen Intent: TickerActivity Spin up app process Create TickerActivity instance
  15. Activity Manager Activity Manager User clicks Ticker icon on Launch

    Screen Intent: TickerActivity Spin up app process Create TickerActivity instance Move TickerActivity to Running state
  16. Activity Manager Activity Manager User clicks Ticker icon on Launch

    Screen Intent: TickerActivity Spin up app process Create TickerActivity instance Move TickerActivity to Running state
  17. Android OS App Processes Launcher Contacts

  18. Android OS TerrificTicker App Processes Launcher Contacts

  19. Android OS TerrificTicker App Processes Launcher Contacts

  20. Android OS TerrificTicker One Foreground Activity Launcher Contacts Running Activity:

    What user sees
  21. Activity Lifecycle

  22. Activity Lifecycle Non- existent Stopped Paused Running Set of states

    Activity can be in
  23. Activity States

  24. Activity States State

  25. Activity States State In memory?

  26. Activity States State In memory? Visible to user?

  27. Activity States State In memory? Visible to user? In foreground?

  28. Activity States State In memory? Visible to user? In foreground?

  29. Activity States State In memory? Visible to user? In foreground?

    Non-Existent No No No
  30. Activity States State In memory? Visible to user? In foreground?

    Non-Existent No No No Stopped Yes No No
  31. Activity States State In memory? Visible to user? In foreground?

    Non-Existent No No No Stopped Yes No No Paused Yes Yes/Partially No
  32. Activity States State In memory? Visible to user? In foreground?

    Non-Existent No No No Stopped Yes No No Paused Yes Yes/Partially No Running (aka Resumed) Yes Yes Yes
  33. Activity in the Wild

  34. Activity Lifecycle

  35. Activity Lifecycle Non- existent Stopped Paused Running Set of states

    Activity can be in
  36. Activity Lifecycle Non- existent Stopped Paused Running Set of states

    Activity can be in Rules about when/how state changes
  37. Activity Lifecycle Non- existent Stopped Paused Running Set of states

    Activity can be in Rules about when/how state changes onDestroy() onCreate() onPause() onResume() onStart() onStop() Set of callback methods
  38. User Launches Activity Lifecycle by Example 1 of 5: “Build-up”

  39. Example: Launch TickerActivity

  40. Example: Launch TickerActivity Press Icon

  41. Example: Launch TickerActivity

  42. Laser Focus: Ticker Activity Android OS

  43. Start in Non-Existent State Non- existent Android OS

  44. User Launches App Non- existent Android OS User presses icon

  45. onCreate() Non- existent Android OS TerrificTicker Process Instance Created Ticker

    Activity mCount = 0 Stopped Instance Created onCreate()
  46. Android OS onStart() Paused onStart() Non- existent Stopped Instance Created

    onCreate() TerrificTicker Process Ticker Activity mCount = 0
  47. onResume() Running onResume() Paused onStart() Non- existent Stopped Instance Created

    onCreate() Android OS TerrificTicker Process Ticker Activity mCount = 0
  48. Pressing Back Lifecycle by Example 2 of 5: “Tear down”

  49. User Increments Count Running onResume() Paused onStart() Non- existent Stopped

    Instance Created onCreate() Android OS TerrificTicker Process Ticker Activity mCount = 0 Press button
  50. User Increments Count Running onResume() Paused onStart() Non- existent Stopped

    Instance Created onCreate() Android OS TerrificTicker Process Ticker Activity mCount = 0 Press button Ticker Activity mCount = 1
  51. User Increments Count Running onResume() Paused onStart() Non- existent Stopped

    Instance Created onCreate() Android OS TerrificTicker Process Ticker Activity mCount = 0 Press button 1 Ticker Activity mCount = 1
  52. User Presses Back Non- existent Stopped Instance Created onCreate() Paused

    Running onResume() onStart() Press Back Android OS TerrificTicker Process Ticker Activity mCount = 1 1
  53. onPause() Non- existent Stopped Instance Created onCreate() Paused Running User

    presses back onPause() onResume() onStart() Android OS TerrificTicker Process Ticker Activity mCount = 1 1
  54. onStop() onStop() Non- existent Stopped Instance Created onCreate() Paused Running

    User presses back onPause() onResume() onStart() Android OS TerrificTicker Process Ticker Activity mCount = 1
  55. onDestroy() onDestroy() Instance Destroyed Non- existent Stopped Instance Created onCreate()

    Paused Running User presses back onPause() onResume() onStart() onStop() Android OS TerrificTicker Process Ticker Activity mCount = 1
  56. onDestroy() onDestroy() Instance Destroyed Non- existent Stopped Instance Created onCreate()

    Paused Running User presses back onPause() onResume() onStart() onStop() Android OS TerrificTicker Process
  57. User Launches App Again Android OS User presses icon TerrificTicker

    Process Non- existent
  58. User Launches App Again Android OS User presses icon TerrificTicker

    Process Non- existent What will the user see? 0 (0) 1 (1)
  59. Answer: (0) Android OS TerrificTicker Process Ticker Activity mCount =

    0 0 Non- existent Stopped onCreate() Paused Running onResume() onStart()
  60. Pressing Home Lifecycle Example 3 of 5: “Switching Tasks”

  61. Increment Count Twice

  62. Increment Count Twice Press home

  63. 1 Increment Count Twice Press home

  64. 1 Increment Count Twice 2 Press home

  65. Home Screen

  66. TickActivity is Running onDestroy() Non- existent Stopped onCreate() Paused Running

    onPause() onResume() onStart() onStop() Android OS TerrificTicker Process Ticker Activity mCount = 2 0 2
  67. User Presses Home onDestroy() Non- existent Stopped onCreate() Paused Running

    onPause() onResume() onStart() onStop() Android OS TerrificTicker Process Ticker Activity mCount = 2 0 2 User presses Home
  68. onPause() onDestroy() Non- existent Stopped onCreate() Paused Running onPause() onResume()

    onStart() onStop() 2 Android OS TerrificTicker Process Ticker Activity mCount = 2
  69. onStop() onDestroy() Non- existent Stopped onCreate() Paused Running onPause() onResume()

    onStart() onStop() Android OS TerrificTicker Process Ticker Activity mCount = 2
  70. User Launches App Again Android OS User presses icon TerrificTicker

    Process Ticker Activity mCount = 2 Stopped
  71. User Launches App Again Android OS User presses icon TerrificTicker

    Process Ticker Activity mCount = 2 Stopped What will the user see? 0 (0) 2 (2)
  72. Answer: (2) onDestroy() Non- existent Stopped onCreate() Paused Running onPause()

    onResume() onStart() onStop() Android OS TerrificTicker Process Ticker Activity mCount = 2 2
  73. Launching Another Activity Lifecycle Example 4 of 5: “Fully occlude

    TickerActivity”
  74. Launch TickerActivity Press Icon

  75. 0 Increment Count Press three times

  76. 0 1 Increment Count Press three times

  77. 0 1 Increment Count 2 Press three times

  78. 0 1 Increment Count 2 Press three times 3

  79. Launch SaveActivity Press Save Count

  80. SaveActivity is Running

  81. From the Start: TickerActivity is Running onDestroy() Non- existent Stopped

    onCreate() Paused Running onPause() onResume() onStart() onStop() Android OS TerrificTicker Process Ticker Activity mCount = 3
  82. Use Presses Save onDestroy() Non- existent Stopped onCreate() Paused Running

    onPause() onResume() onStart() onStop() Android OS TerrificTicker Process Ticker Activity mCount = 3
  83. SaveActivity Launches Android OS TerrificTicker Process Ticker Activity mCount =

    3 Save Activity
  84. TickerActivity: Stopped onDestroy() Non- existent Stopped onCreate() Paused Running onPause()

    onResume() onStart() onStop() Android OS TerrificTicker Process Ticker Activity mCount = 3 Save Activity
  85. User Presses Back onDestroy() Non- existent Stopped onCreate() Paused Running

    onPause() onResume() onStart() onStop() Android OS TerrificTicker Process Ticker Activity mCount = 3 Save Activity
  86. SaveActivity is Destroyed Android OS TerrificTicker Process Ticker Activity mCount

    = 3 Save Activity
  87. SaveActivity is Destroyed Android OS TerrificTicker Process Ticker Activity mCount

    = 3
  88. Ticker Activity Moves to Stopped from Running Android OS TerrificTicker

    Process Ticker Activity mCount = 3 onDestroy() Non- existent Stopped onCreate() Paused Running onPause() onResume() onStart() onStop()
  89. onStart() onStart() Android OS TerrificTicker Process Ticker Activity mCount =

    3 onDestroy() Non- existent Stopped onCreate() Paused Running onPause() onResume() onStop()
  90. onStart() onStart() Android OS TerrificTicker Process Ticker Activity mCount =

    3 onDestroy() Non- existent Stopped onCreate() Paused Running onPause() onResume() onStop()
  91. onStart() onResume() Android OS TerrificTicker Process Ticker Activity mCount =

    3 onDestroy() Non- existent Stopped onCreate() Paused Running onPause() onResume() onStop()
  92. Launching a Transparent Activity Lifecycle Example 5 of 5: “Partially

    occlude TickerActivity”
  93. Launch SaveActivity Press Save Count

  94. SaveActivity is Running

  95. From the Start: TickerActivity is Running onDestroy() Non- existent Stopped

    onCreate() Paused Running onPause() onResume() onStart() onStop() Android OS TerrificTicker Process Ticker Activity mCount = 3
  96. Use Presses Save onDestroy() Non- existent Stopped onCreate() Paused Running

    onPause() onResume() onStart() onStop() Android OS TerrificTicker Process Ticker Activity mCount = 3
  97. SaveActivity Launches Android OS TerrificTicker Process Ticker Activity mCount =

    3 Save Activity
  98. TickerActivity: Paused onDestroy() Non- existent Stopped onCreate() Paused Running onPause()

    onResume() onStart() onStop() Android OS TerrificTicker Process Ticker Activity mCount = 3 Save Activity
  99. User Presses Back Android OS TerrificTicker Process Ticker Activity mCount

    = 3 Save Activity onDestroy() Non- existent Stopped onCreate() Paused Running onPause() onResume() onStart() onStop()
  100. User Presses Back Android OS TerrificTicker Process Ticker Activity mCount

    = 3 onDestroy() Non- existent Stopped onCreate() Paused Running onPause() onResume() onStart() onStop()
  101. TickerActivity: Running onDestroy() Non- existent Stopped onCreate() Paused Running onPause()

    onResume() onStart() onStop() Android OS TerrificTicker Process Ticker Activity mCount = 3
  102. Lifecycle Summary Exists? Visible? Foreground?

  103. Activity Lifecycle onDestroy() Non- existent Stopped onCreate() Paused Running onPause()

    onResume() onStart() onStop()
  104. Entire Lifetime (Instance Lifetime) Instance Lifetime onDestroy() Non- existent Stopped

    onCreate() Paused Running onPause() onResume() onStart() onStop()
  105. Entire Lifetime Visible Lifetime Visible Lifetime onDestroy() Non- existent Stopped

    onCreate() Paused Running onPause() onResume() onStart() onStop()
  106. Entire Lifetime Foreground Lifetime Visible Lifetime onDestroy() Non- existent Stopped

    onCreate() Foreground Lifetime Paused Running onPause() onResume() onStart() onStop()
  107. Going Home, Revisited A Cautionary Tale

  108. Launch TickerActivity

  109. Do Lots of Work 42

  110. Press Home 42

  111. Launch Pokemon Go

  112. Play Pokemon GO

  113. Press Home

  114. Press Ticker Icon

  115. Launch Ticker

  116. Launch Ticker

  117. User Presses Home onDestroy() Non- existent Stopped onCreate() Paused Running

    onPause() onResume() onStart() onStop() User presses home 3 Android OS TerrificTicker Process Ticker Activity mCount = 3
  118. onPause() onDestroy() Non- existent Stopped onCreate() Paused Running onPause() onResume()

    onStart() onStop() 3 Android OS TerrificTicker Process Ticker Activity mCount = 3
  119. onStop() onDestroy() Non- existent Stopped onCreate() Paused Running onPause() onResume()

    onStart() onStop() Android OS TerrificTicker Process Ticker Activity mCount = 3
  120. User Plays Pokemon GO onDestroy() Non- existent Stopped onCreate() Paused

    Running onPause() onResume() onStart() onStop() Android OS TerrificTicker Process Ticker Activity mCount = 3 Pokemon GO Process VideoActivity
  121. Uh oh… onDestroy() Non- existent Stopped onCreate() Paused Running onPause()

    onResume() onStart() onStop() Android OS TerrificTicker Process Ticker Activity mCount = 3 VideoPlayer Process VideoActivity
  122. Ticker Process Gets Killed onDestroy() Non- existent Stopped onCreate() Paused

    Running onPause() onResume() onStart() onStop() X Android OS TerrificTicker Process Ticker Activity mCount = 3 VideoPlayer Process VideoActivity X
  123. TickerActivity Jumps to Non- Existent onDestroy() Non- existent Stopped onCreate()

    Paused Running onPause() onResume() onStart() onStop() X Android OS VideoPlayer Process VideoActivity
  124. Saving Transient State onSaveInstanceState to the rescue

  125. onSaveInstanceState() public class TickerActivity extends AppCompatActivity {
 
 private static

    final String KEY_TICKER_COUNT = "ticker_count";
 ...
 
 @Override
 protected void onSaveInstanceState(Bundle outState) {
 super.onSaveInstanceState(outState);
 outState.putInt(KEY_TICKER_COUNT, mCount);
 } ...
 }

  126. public class TickerActivity extends AppCompatActivity {
 
 ... 
 @Override


    protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_ticker);
 setupUI();
 
 if (savedInstanceState != null) {
 mCount = savedInstanceState.getInt(KEY_TICKER_COUNT, 0);
 }
 
 updateUI();
 } ...
 }
 Using State Bundle
  127. Activity Record Stored 3 Activity Record Store Instance A

  128. Activity Record Stored 3 Activity Record Store onSaveInstanceState ticker_count: 3

    Instance A
  129. Activity Record Stored 3 Activity Record Store onSaveInstanceState ticker_count: 3

    TerrificTicker Instance A Record ticker_count: 3 Instance A
  130. Process Gets Killed Activity Record Store TerrificTicker Instance A Record

    ticker_count: 3
  131. User Launches App Activity Record Store TerrificTicker Instance A Record

    ticker_count: 3
  132. User Launches App Activity Record Store TerrificTicker Instance A Record

    ticker_count: 3 onCreate ticker_count: 3
  133. User Launches App Activity Record Store TerrificTicker Instance A Record

    ticker_count: 3 3 Recreated Instance A onCreate ticker_count: 3
  134. User Launches App Activity Record Store 3 Recreated Instance A

    onCreate ticker_count: 3
  135. User Launches App Activity Record Store 3 Recreated Instance A

  136. Full Circle

  137. Structuring your Activity What to put in each callback?

  138. onCreate • call setContentView() • “hook up” UI widgets •

    check for saved state bundle
  139. onPause • save vital data • typically stop animations or

    other things consuming CPU • should be quick
  140. onStop • persist vital data • last guaranteed teardown method

  141. onDestroy • last place to free resources • not guaranteed

    to be called
  142. But Also… • It depends!

  143. Reasoning About the Lifecycle What to put in each callback?

  144. Displaying Location • Show user their location • Minimize battery

    usage • Maximize precision when user is actively looking at my map
  145. Displaying Location: Which Callbacks? • Start sampling - onStart •

    Set higher sampling rate/accuracy - onResume • Set lower sampling rate/accuracy - onPause • Stop sampling - onStop onDestroy() Non- existent Stopped onCreate() Paused Running onPause() onResume() onStart() onStop()
  146. Video Playback

  147. Video Playback • User starts video activity • User presses

    a transparent settings activity • video should keep playing!
  148. Video Playback: Which Callbacks? • initialize player - onCreate •

    start playback - onStart • stop playback - onStop • release player resources - onDestroy
  149. Capstone Challenge What state are these activities in?

  150. Challenge: Multi-Window What state is each in?

  151. Next Steps

  152. @kristinmars github.com/kristinmars bignerdranch.com