Slide 1

Slide 1 text

Activities, Intents, Tasks, and the Back Stack Matt Logan

Slide 2

Slide 2 text

Activities class HomeActivity : AppCompatActivity() {
 
 override fun onCreate(savedInstanceState: Bundle?) {
 super.onCreate(savedInstanceState)
 setContentView(R.layout.activity_home)
 }
 }

Slide 3

Slide 3 text

Activities class HomeActivity : AppCompatActivity() {
 
 override fun onCreate(savedInstanceState: Bundle?) {
 super.onCreate(savedInstanceState)
 setContentView(R.layout.activity_home)
 }
 } Entry point

Slide 4

Slide 4 text

Activities class HomeActivity : AppCompatActivity() {
 
 override fun onCreate(savedInstanceState: Bundle?) {
 super.onCreate(savedInstanceState)
 setContentView(R.layout.activity_home)
 }
 } UI

Slide 5

Slide 5 text

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)
 }
 }


Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

Activities • Entry point to your app • UI building block • Navigation

Slide 8

Slide 8 text

How do activities handle navigation?

Slide 9

Slide 9 text

Intents @OnClick(R.id.view_trip_button)
 fun onViewTripButtonClicked() {
 val tripActivity = Intent(this, TripActivity!::class.java)
 startActivity(tripActivity)
 }

Slide 10

Slide 10 text

Intents @OnClick(R.id.view_trip_button)
 fun onViewTripButtonClicked() {
 val tripActivity = Intent(this, TripActivity!::class.java)
 startActivity(tripActivity)
 }

Slide 11

Slide 11 text

Intents Intent(Context packageContext, Class> cls) Package context (where to look) Class of activity to start

Slide 12

Slide 12 text

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)
 }
 }

Slide 13

Slide 13 text

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)
 }
 }

Slide 14

Slide 14 text

Intents Intent(String action) Action to fulfill, like capturing an image

Slide 15

Slide 15 text

Intents • Navigation within your app • Navigation between apps • Can also pass data (we didn’t cover this)

Slide 16

Slide 16 text

What if we want to navigate backward?

Slide 17

Slide 17 text

Tasks Home Trip details Camera

Slide 18

Slide 18 text

Tasks Home Trip details Camera

Slide 19

Slide 19 text

Tasks HomeActivity TripActivity WeatherService TripProvider CameraActivity UploadService DownloadService GalleryActivity Travel app APK Camera app APK

Slide 20

Slide 20 text

Tasks HomeActivity TripActivity WeatherService TripProvider CameraActivity UploadService DownloadService GalleryActivity Travel app APK Camera app APK

Slide 21

Slide 21 text

Tasks • Collection of activities • Associated with a “back stack” of UI history • Can span multiple processes & APKs • Customized with intent flags & manifest attributes

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

Launch modes Home Trip details Camera Task A Task B

Slide 26

Slide 26 text

Launch modes Home Trip Details Camera Task A Task B

Slide 27

Slide 27 text

Launch modes intent.addFlags(
 FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_MULTIPLE_TASK) Kotlin: intent.addFlags(
 FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK); Java:

Slide 28

Slide 28 text

Launch modes intent.addFlags(
 FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_MULTIPLE_TASK) Kotlin: intent.addFlags(
 FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK); Java: Bitwise “or” operator

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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)
 }

Slide 33

Slide 33 text

Launch modes @OnClick(R.id.open_camera_button)
 fun onOpenCameraButtonClicked() {
 val cameraIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
 cameraIntent.addFlags(402_653_184) 
 startActivity(cameraIntent)
 } Don't do this!

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

Launch modes Home Trip details onNewIntent() FLAG_ACTIVITY_SINGLE_TOP

Slide 36

Slide 36 text

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)
 }

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

Launch modes Home Trip details FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_NEW_TASK Weather home Weather details Weather forecast

Slide 39

Slide 39 text

Launch modes Home Trip details Weather home Weather details onNewIntent() FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_NEW_TASK

Slide 40

Slide 40 text

Launch modes

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

Task affinity

Slide 43

Slide 43 text

Task affinity af·fin·i·ty noun a spontaneous or natural liking or sympathy for someone or something. “Matt has an affinity for pizza.”

Slide 44

Slide 44 text

Task affinity af·fin·i·ty noun an indication of which task an activity prefers to belong to.

Slide 45

Slide 45 text

Task affinity • Useful with FLAG_ACTIVITY_NEW_TASK • Activity gets launched into task of activities with the same affinity

Slide 46

Slide 46 text

Task affinity Home Trip details taskAffinity="tripTask" Weather details taskAffinity="tripTask" Weather home

Slide 47

Slide 47 text

Task affinity • Relevant when allowTaskReparenting="true" • Activity can be reassigned tasks as needed

Slide 48

Slide 48 text

Task affinity Home Trip details Weather home Weather details allowTaskReparenting="true"

Slide 49

Slide 49 text

Task affinity Home Trip details Weather home Weather details allowTaskReparenting="true"

Slide 50

Slide 50 text

Task affinity • One more use case • Two “apps” in one APK • Use affinities to separate activities into tasks

Slide 51

Slide 51 text

Task affinity 


Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

Clearing the back stack Prevents clearing of activities from task

Slide 54

Slide 54 text

Clearing the back stack Removes all activities except root when user returns to task

Slide 55

Slide 55 text

Clearing the back stack Same as clearTaskOnLaunch but only operates on a single activity

Slide 56

Slide 56 text

Task helpers • NavUtils has some navigation helper methods • navigateUpTo(Activity, Intent) • navigateUpFromSameTask(Activity) • getParentActivityIntent(Activity)

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

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”

Slide 59

Slide 59 text

How does all of this work?

Slide 60

Slide 60 text

How’s it work? • Intents are handled by ActivityManagerService • One of several system services • Orchestrates activities, including tasks and their respective back stacks

Slide 61

Slide 61 text

How’s it work? val activityManager =
 getSystemService(ACTIVITY_SERVICE) as ActivityManager What about this activity manager?

Slide 62

Slide 62 text

How’s it work? • ActivityManagerService is a system service • ActivityManager is for app developers

Slide 63

Slide 63 text

How’s it work? • ActivityManager • Some methods are broadly useful: • isLowRamDevice() • clearApplicationUserData() • Apps can interact with its task stack via: • ActivityManager.AppStack • ActivityManager.RecentTaskInfo

Slide 64

Slide 64 text

Why does Android work this way?

Slide 65

Slide 65 text

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

Slide 66

Slide 66 text

What if we want to handle navigation without involving the Android OS?

Slide 67

Slide 67 text

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

Slide 68

Slide 68 text

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!

Slide 69

Slide 69 text

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

Slide 70

Slide 70 text

Thanks! @_mattlogan Twitter mattlogan.me Blog & links github.com/mattlogan Open source