Activities, Intents, Tasks, and the Back Stack (360|AnDev, July 2017)

Activities, Intents, Tasks, and the Back Stack (360|AnDev, July 2017)

The Android operating system is unique in the way that it manages the series of screens with which a user can interact. Generally, we know these “screens” as activities, though we can make exceptions for smaller components like fragments and views. As application developers, we create activities and move between them with intents. However, the way that Android uses intents to create, destroy, and maintain a “stack” of Activities is mostly hidden from us — for good reason! In this talk, we’ll work towards a solid understanding of activities, intents, tasks, and the back stack. We may also take a quick look into the mechanisms by which the Android operating system orchestrates all of these things internally.

8d9b8aa31d299a7bc2211f4a4a517215?s=128

Matt Logan

July 13, 2017
Tweet

Transcript

  1. 2.

    Activities class HomeActivity : AppCompatActivity() {
 
 override fun onCreate(savedInstanceState:

    Bundle?) {
 super.onCreate(savedInstanceState)
 setContentView(R.layout.activity_home)
 }
 }
  2. 3.

    Activities class HomeActivity : AppCompatActivity() {
 
 override fun onCreate(savedInstanceState:

    Bundle?) {
 super.onCreate(savedInstanceState)
 setContentView(R.layout.activity_home)
 }
 } Entry point
  3. 4.

    Activities class HomeActivity : AppCompatActivity() {
 
 override fun onCreate(savedInstanceState:

    Bundle?) {
 super.onCreate(savedInstanceState)
 setContentView(R.layout.activity_home)
 }
 } UI
  4. 5.

    Activities class HomeActivity : AppCompatActivity() {
 
 override fun onCreate(savedInstanceState:

    Bundle?) {
 super.onCreate(savedInstanceState)
 setContentView(R.layout.activity_main)
 }
 
 @OnClick(R.id.view_trip_button) fun onViewTripButtonClicked() {
 val tripActivity = Intent(this, TripActivity!::class.java)
 startActivity(tripActivity)
 }
 }

  5. 6.

    Activities class HomeActivity : AppCompatActivity() {
 
 override fun onCreate(savedInstanceState:

    Bundle?) {
 super.onCreate(savedInstanceState)
 setContentView(R.layout.activity_main)
 }
 
 @OnClick(R.id.view_trip_button) fun onViewTripButtonClicked() {
 val tripActivity = Intent(this, TripActivity!::class.java)
 startActivity(tripActivity)
 }
 }
 Navigation
  6. 12.

    Intents class TripActivity : AppCompatActivity() {
 
 override fun onCreate(savedInstanceState:

    Bundle?) {
 super.onCreate(savedInstanceState)
 setContentView(R.layout.activity_trip)
 }
 
 @OnClick(R.id.open_camera_button)
 fun onOpenCameraButtonClicked() {
 val cameraIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
 startActivity(cameraIntent)
 }
 }
  7. 13.

    Intents class TripActivity : AppCompatActivity() {
 
 override fun onCreate(savedInstanceState:

    Bundle?) {
 super.onCreate(savedInstanceState)
 setContentView(R.layout.activity_trip)
 }
 
 @OnClick(R.id.open_camera_button)
 fun onOpenCameraButtonClicked() {
 val cameraIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
 startActivity(cameraIntent)
 }
 }
  8. 15.

    Intents • Navigation within your app • Navigation between apps

    • Can also pass data (we didn’t cover this)
  9. 21.

    Tasks • Collection of activities • Associated with a “back

    stack” of UI history • Can span multiple processes & APKs • Customized with intent flags & manifest attributes
  10. 24.

    Launch modes • FLAG_ACTIVITY_NEW_TASK • Starts activity in a new

    task • If activity is already running in a task, will reuse existing task • Unless paired with FLAG_ACTIVITY_MULTIPLE_TASK
  11. 29.

    Launch modes public static final int FLAG_ACTIVITY_NEW_TASK = 0x10000000; public

    static final int FLAG_ACTIVITY_MULTIPLE_TASK = 0x08000000; val flags = FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_MULTIPLE_TASK
  12. 30.

    Launch modes = 0000 1000 0000 0000 0000 0000 0000

    0000 = 0001 0000 0000 0000 0000 0000 0000 0000 public static final int FLAG_ACTIVITY_NEW_TASK = 0x10000000; public static final int FLAG_ACTIVITY_MULTIPLE_TASK = 0x08000000; val flags = FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_MULTIPLE_TASK
  13. 31.

    Launch modes public static final int FLAG_ACTIVITY_NEW_TASK = 0x10000000; =

    0000 1000 0000 0000 0000 0000 0000 0000 = 0001 0000 0000 0000 0000 0000 0000 0000 public static final int FLAG_ACTIVITY_MULTIPLE_TASK = 0x08000000; val flags = FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_MULTIPLE_TASK = 0001 1000 0000 0000 0000 0000 0000 0000 = 402,653,184 Result Result
  14. 32.

    Launch modes @OnClick(R.id.open_camera_button)
 fun onOpenCameraButtonClicked() {
 val cameraIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)


    cameraIntent.addFlags(FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_MULTIPLE_TASK)
 startActivity(cameraIntent)
 }
  15. 34.

    Launch modes • FLAG_ACTIVITY_SINGLE_TOP • Activity won’t be launched if

    already at top • Intent will be delivered to existing activity via onNewIntent(Intent) callback
  16. 36.

    Launch modes override fun onNewIntent(intent: Intent) {
 super.onNewIntent(intent)
 
 !//

    Get data from new intent 
 val newTripName = intent.extras.getString(EXTRA_TRIP_NAME)
 
 !// Clear existing UI and repopulate with new data
 refreshUi(newTripName)
 }
  17. 37.

    Launch modes • FLAG_ACTIVITY_CLEAR_TOP • Destroys everything on top if

    it already exists • Can be used with FLAG_ACTIVITY_NEW_TASK • Locates activity in any task • Destroys all activities on top • Activity is brought to foreground
  18. 39.

    Launch modes Home Trip details Weather home Weather details onNewIntent()

    FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_NEW_TASK
  19. 41.

    Launch modes • "standard" — new instance in current task

    • "singleTop" — won’t be launched if already at top • "singleTask" — creates new task for activity • "singleInstance" — no other activities can be launched into same task • Can be overridden with intent flags
  20. 43.

    Task affinity af·fin·i·ty noun a spontaneous or natural liking or

    sympathy for someone or something. “Matt has an affinity for pizza.”
  21. 45.
  22. 50.

    Task affinity • One more use case • Two “apps”

    in one APK • Use affinities to separate activities into tasks
  23. 52.

    Clearing the back stack • Default behavior: • After some

    amount of time, system clears all activities in task except the root • User has likely abandoned that task • Modified with more manifest attributes
  24. 56.

    Task helpers • NavUtils has some navigation helper methods •

    navigateUpTo(Activity, Intent) • navigateUpFromSameTask(Activity) • getParentActivityIntent(Activity)
  25. 57.

    Task helpers • TaskStackBuilder lets you create a back stack

    manually • Useful when starting activity in a new task with no UI history • Lets build the typical UI history that would lead the user to that point
  26. 58.

    Recents • Back button should never traverse tasks • User

    can switch tasks with “recents” system UI • Basically a view of all tasks • Special behavior added in Lollipop for “documents”
  27. 60.

    How’s it work? • Intents are handled by ActivityManagerService •

    One of several system services • Orchestrates activities, including tasks and their respective back stacks
  28. 63.

    How’s it work? • ActivityManager • Some methods are broadly

    useful: • isLowRamDevice() • clearApplicationUserData() • Apps can interact with its task stack via: • ActivityManager.AppStack • ActivityManager.RecentTaskInfo
  29. 65.

    Design considerations • Android OS operates on modular components •

    Enforces separation of concerns at application level and at device level • Navigation is handled by the OS, not your app • Allows for navigation model involving activities in separate APKs
  30. 67.

    In-app navigation • Official, supported solution: fragments • FragmentManager &

    FragmentTransaction take the place of ActivityManagerService & intents • Lifecycle methods very similar to Activity • Fragment back stack similar to task back stack • Built in state restoration • Support for animated transitions
  31. 68.

    In-app navigation • Non-fragment solutions • Can avoid some complexity

    of fragments • Manually add & remove views to & from a root view group • You have to maintain a navigation stack yourself!
  32. 69.

    Resources Android “Activities — Tasks and Back Stack” developer guide

    https://developer.android.com/guide/components/activities/tasks-and-back-stack.html Dan Morrill’s 2008 Google I/O talk: Inside the Android Application Framework https://www.youtube.com/watch?v=TkPiXRNee7A Anatomy of Android: Activity Manager https://anatomyofandroid.com/2013/10/16/activity-manager/ The Cheese Factory: Understand Android Activity’s launchMode https://inthecheesefactory.com/blog/understand-android-activity-launchmode/en Android Programming: The Big Nerd Ranch Guide https://www.bignerdranch.com/books/android-programming/ Square Engineering Blog: Advocating Against Android Fragments https://medium.com/square-corner-blog/advocating-against-android-fragments-81fd0b462c97