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.

Kristin Marsicano

October 21, 2016
Tweet

More Decks by Kristin Marsicano

Other Decks in Technology

Transcript

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

    lifecycle so you can provide a smooth user experience
  2. 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:
  3. Activity Manager Activity Manager User clicks Ticker icon on Launch

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

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

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

    Screen Intent: TickerActivity Spin up app process Create TickerActivity instance Move TickerActivity to Foreground
  7. Activity States State In memory? Visible to user? In foreground?

    Non-Existent No No No Stopped Yes No No Paused Yes Yes/Partially No
  8. 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
  9. Activity Lifecycle Non- existent Stopped Paused Resumed Set of states

    Activity can be in Rules about when/how state changes
  10. 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
  11. onCreate() Non- existent Android OS TerrificTicker Process Instance Created Ticker

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

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

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

    Instance Created onCreate() Android OS TerrificTicker Process Ticker Activity mCount = 0 Press button
  15. 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
  16. 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
  17. User Presses Back Non- existent Stopped Instance Created onCreate() Paused

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

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

    User presses back onPause() onResume() onStart() Android OS TerrificTicker Process Ticker Activity mCount = 1
  20. 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
  21. onDestroy() onDestroy() Instance Destroyed Non- existent Stopped Instance Created onCreate()

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

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

    0 0 Non- existent Stopped onCreate() Paused Resumed onResume() onStart()
  24. TickActivity is Running onDestroy() Non- existent Stopped onCreate() Paused Resumed

    onPause() onResume() onStart() onStop() Android OS TerrificTicker Process Ticker Activity mCount = 2 0 2
  25. 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
  26. onPause() onDestroy() Non- existent Stopped onCreate() Paused Resumed onPause() onResume()

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

    onStart() onStop() Android OS TerrificTicker Process Ticker Activity mCount = 2
  28. 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)
  29. Answer: (2) onDestroy() Non- existent Stopped onCreate() Paused Resumed onPause()

    onResume() onStart() onStop() Android OS TerrificTicker Process Ticker Activity mCount = 2 2
  30. 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
  31. Use Presses Save onDestroy() Non- existent Stopped onCreate() Paused Resumed

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

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

    onPause() onResume() onStart() onStop() Android OS TerrificTicker Process Ticker Activity mCount = 3 Save Activity
  34. 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()
  35. onStart() onStart() Android OS TerrificTicker Process Ticker Activity mCount =

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

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

    3 onDestroy() Non- existent Stopped onCreate() Paused Resumed onPause() onResume() onStop()
  38. 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
  39. Use Presses Save onDestroy() Non- existent Stopped onCreate() Paused Resumed

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

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

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

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

    onResume() onStart() onStop() Android OS TerrificTicker Process Ticker Activity mCount = 3
  44. Entire Lifetime (Instance Lifetime) Instance Lifetime onDestroy() Non- existent Stopped

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

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

    onCreate() Foreground Lifetime Paused Running onPause() onResume() onStart() onStop()
  47. 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
  48. onPause() onDestroy() Non- existent Stopped onCreate() Paused Running onPause() onResume()

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

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

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

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

    onStart() onStop() X Android OS VideoPlayer Process VideoActivity X
  55. 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);
 } ...
 }

  56. 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
  57. Activity Record Stored 3 Activity Record Store onSaveInstanceState ticker_count: 3

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

    ticker_count: 3 3 Recreated Instance A onCreate ticker_count: 3
  59. onPause • save vital data (pre-Honeycomb) • typically stop animations

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

    stop animations or other things consuming CPU (in a multi-window world) • should be quick
  61. Entire Lifetime Foreground Lifetime Visible Lifetime onDestroy() Non- existent Stopped

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

    battery usage • Maximize precision when user is actively looking at my map
  63. 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()
  64. 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()
  65. 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()
  66. 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()
  67. 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()
  68. 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()
  69. 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()
  70. 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()
  71. Video Playback • Play video whenever player is visible •

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

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

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

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

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

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

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

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

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

    > 23: onStart • <= 23: onResume • Pause playback not visible • > 23: onStop • <= 23: onPause
  81. @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
 }
 }