Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Activities in the Wild: Exploring the Activity Lifecycle (Connect.Tech, October 2016)

Activities in the Wild: Exploring the Activity Lifecycle (Connect.Tech, October 2016)

[This version of the talk includes more details about handling multi-window scenarios. You can view a video of the presentation here: https://www.youtube.com/watch?v=Q5FWJGHuDwA]

To Android users, your Activity object is your app. Take a journey with me to experience what happens to your Activity’s state and view at runtime in relation to what the user (and the operating system itself) is doing. We will discuss considerations you should make based on this knowledge when designing and building your app. You will walk away from this talk with a strong understanding of the most fundamental piece of Android applications.

0f97fa53edac850ba4c64c2df5bd9fb1?s=128

Kristin Marsicano

October 21, 2016
Tweet

More Decks by Kristin Marsicano

Other Decks in Technology

Transcript

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

    @kristinmars Big Nerd Ranch
  2. Demo: Multi-Tasking

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

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

  7. 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:
  8. Activity Manager

  9. Activity Manager User clicks Ticker icon on Launch Screen

  10. Activity Manager User clicks Ticker icon on Launch Screen

  11. 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
  14. Activity Manager Activity Manager User clicks Ticker icon on Launch

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

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

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

    Screen Intent: TickerActivity Spin up app process Create TickerActivity instance Move TickerActivity to Foreground
  18. Android OS App Processes Launcher Contacts

  19. Android OS TerrificTicker App Processes Launcher Contacts

  20. Android OS TerrificTicker App Processes Launcher Contacts

  21. Android OS TerrificTicker One Foreground Activity Launcher Contacts Foreground Activity:

    What user sees
  22. Activity Lifecycle

  23. Activity Lifecycle Non- existent Stopped Paused Resumed Set of states

    Activity can be in
  24. Activity States

  25. Activity States State

  26. Activity States State In memory?

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

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

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

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

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

    Non-Existent No No No Stopped Yes No 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
  33. Activity States State In memory? Visible to user? In foreground?

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

  35. Activity in the Wild

  36. Activity Lifecycle

  37. Activity Lifecycle Non- existent Stopped Paused Resumed Set of states

    Activity can be in
  38. Activity Lifecycle Non- existent Stopped Paused Resumed Set of states

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

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

  41. Example: Launch TickerActivity

  42. Example: Launch TickerActivity Press Icon

  43. Example: Launch TickerActivity

  44. Laser Focus: Ticker Activity Android OS

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

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

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

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

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

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

  51. User Increments Count Resumed onResume() Paused onStart() Non- existent Stopped

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

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

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

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

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

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

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

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

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

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

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

  63. Increment Count Twice

  64. 1 Increment Count Twice

  65. 1 Increment Count Twice 2

  66. 1 Increment Count Twice 2 Press home

  67. Home Screen

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

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

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

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

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

    Process Ticker Activity mCount = 2 Stopped
  73. 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)
  74. Answer: (2) onDestroy() Non- existent Stopped onCreate() Paused Resumed onPause()

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

    TickerActivity”
  76. Launch TickerActivity Press Icon

  77. 0 Increment Count Press three times

  78. 0 1 Increment Count Press three times

  79. 0 1 Increment Count 2 Press three times

  80. 0 1 Increment Count 2 Press three times 3

  81. Launch SaveActivity Press Save Count

  82. SaveActivity is Running

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

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

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

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

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

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

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

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

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

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

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

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

    occlude TickerActivity”
  95. Launch SaveActivity Press Save Count

  96. SaveActivity is Running

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

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

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

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

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

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

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

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

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

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

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

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

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

  110. Launch TickerActivity

  111. Do Lots of Work 42

  112. Press Home 42

  113. Launch Pokemon Go

  114. Play Pokemon GO

  115. Press Home

  116. Press Ticker Icon

  117. Launch Ticker

  118. Launch Ticker

  119. 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
  120. onPause() onDestroy() Non- existent Stopped onCreate() Paused Running onPause() onResume()

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

    onStart() onStop() Android OS TerrificTicker Process Ticker Activity mCount = 3
  122. 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
  123. Uh oh… onDestroy() Non- existent Stopped onCreate() Paused Running onPause()

    onResume() onStart() onStop() Android OS TerrificTicker Process Ticker Activity mCount = 3 VideoPlayer Process VideoActivity
  124. 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
  125. TickerActivity Jumps to Non- Existent onDestroy() Non- existent Stopped onCreate()

    Paused Running onPause() onResume() onStart() onStop() X Android OS VideoPlayer Process VideoActivity
  126. Pre-Honeycomb onDestroy() Non- existent Stopped onCreate() Paused Running onPause() onResume()

    onStart() onStop() X Android OS VideoPlayer Process VideoActivity X
  127. Saving Transient State onSaveInstanceState to the rescue

  128. 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);
 } ...
 }

  129. 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
  130. Activity Record Stored 3 Activity Record Store Instance A

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

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

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

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

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

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

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

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

  139. Full Circle

  140. Full Circle

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

  142. Lifecycle Pairs • onCreate / onDestroy • onStart / onStop

    • onResume / onPause
  143. onCreate • call setContentView() • “hook up” UI widgets •

    check for saved state bundle
  144. onPause • save vital data (pre-Honeycomb) • typically stop animations

    or other things consuming CPU (pre-Nougat) • should be quick
  145. onStop • save vital data (Honeycomb and beyond) • typically

    stop animations or other things consuming CPU (in a multi-window world) • should be quick
  146. onDestroy • last place to free resources

  147. But Also… • It depends!

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

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

  150. Entire Lifetime Foreground Lifetime Visible Lifetime onDestroy() Non- existent Stopped

    onCreate() Foreground Lifetime Paused Running onPause() onResume() onStart() onStop()
  151. Example: Displaying Location • Show user their location • Minimize

    battery usage • Maximize precision when user is actively looking at my map
  152. Displaying Location: Which Callbacks? • Start sampling when visible •

    Increase accuracy when in foreground • Set lower sampling rate/accuracy • Stop sampling - onStop onDestroy() Non- existent Stopped onCreate() Paused Running onPause() onResume() onStart() onStop()
  153. Displaying Location: Which Callbacks? • Start sampling when visible onStart

    • Increase accuracy when in foreground • Set lower sampling rate/accuracy • Stop sampling - onStop onDestroy() Non- existent Stopped onCreate() Paused Running onPause() onResume() onStart() onStop()
  154. Displaying Location: Which Callbacks? • Start sampling when visible onStart

    • Increase accuracy when in foreground • Set lower sampling rate/accuracy • Stop sampling - onStop onDestroy() Non- existent Stopped onCreate() Paused Running onPause() onResume() onStart() onStop()
  155. Displaying Location: Which Callbacks? • Start sampling when visible onStart

    • Increase accuracy when in foreground onResume • Set lower sampling rate/accuracy • Stop sampling - onStop onDestroy() Non- existent Stopped onCreate() Paused Running onPause() onResume() onStart() onStop()
  156. Displaying Location: Which Callbacks? • Start sampling when visible onStart

    • Increase accuracy when in foreground onResume • Decrease accuracy when in background • Stop sampling - onStop onDestroy() Non- existent Stopped onCreate() Paused Running onPause() onResume() onStart() onStop()
  157. Displaying Location: Which Callbacks? • Start sampling when visible onStart

    • Increase accuracy when in foreground onResume • Decrease accuracy when in background onPause • Stop sampling - onStop onDestroy() Non- existent Stopped onCreate() Paused Running onPause() onResume() onStart() onStop()
  158. Displaying Location: Which Callbacks? • Start sampling when visible onStart

    • Increase accuracy when in foreground onResume • Decrease accuracy when in background onPause • Stop sampling onDestroy() Non- existent Stopped onCreate() Paused Running onPause() onResume() onStart() onStop()
  159. Displaying Location: Which Callbacks? • Start sampling when visible onStart

    • Increase accuracy when in foreground onResume • Decrease accuracy when in background onPause • Stop sampling onStop onDestroy() Non- existent Stopped onCreate() Paused Running onPause() onResume() onStart() onStop()
  160. Video Playback • Play video whenever player is visible •

    Stop playing video when player is not visible
  161. Video Playback: Which Callbacks? • Initialize player onCreate • Start

    playback when visible - onStart • Pause playback not visible - onStop • Release player when user dismisses player - onDestroy
  162. Video Playback: Which Callbacks? • Initialize player onCreate • Start

    playback when visible • Pause playback not visible - onStop • Release player when user dismisses player - onDestroy
  163. Video Playback: Which Callbacks? • Initialize player onCreate • Start

    playback when visible onStart • Pause playback not visible - onStop • Release player when user dismisses player - onDestroy
  164. Video Playback: Which Callbacks? • Initialize player onCreate • Start

    playback when visible onStart • Pause playback not visible • Release player when user dismisses player - onDestroy
  165. Video Playback: Which Callbacks? • Initialize player onCreate • Start

    playback when visible onStart • Pause playback not visible onStop • Release player when user dismisses player - onDestroy
  166. Video Playback: Which Callbacks? • Initialize player onCreate • Start

    playback when visible onStart • Pause playback not visible onStop • Release resources when user dismisses player onDestroy
  167. Video Playback: Which Callbacks? • Initialize player onCreate • Start

    playback when visible onStart • Pause playback not visible onStop • Release resources when user dismisses player onDestroy
  168. Stop used to be lazy! Pre-Nougat: onStop() can occur a

    short time after activity disappears from view
  169. Video Playback: Which Callbacks? • Start playback when visible •

    > 23: onStart • <= 23: onResume • Pause playback not visible • > 23: onStop • <= 23: onPause
  170. @Override
 public void onStart() {
 super.onStart();
 if (Util.SDK_INT > 23)

    {
 // play
 }
 }
 
 @Override
 public void onResume() {
 super.onResume();
 if ((Util.SDK_INT <= 23 || player == null)) {
 // play
 }
 }
 
 @Override
 public void onPause() {
 super.onPause();
 if (Util.SDK_INT <= 23) {
 // pause
 }
 }
 
 @Override
 public void onStop() {
 super.onStop();
 if (Util.SDK_INT > 23) {
 // pause
 }
 }
  171. Next Steps

  172. @kristinmars github.com/kristinmars bignerdranch.com