Skip to content

Instantly share code, notes, and snippets.

@jwill
Last active August 29, 2015 14:02

Revisions

  1. jwill revised this gist Jun 20, 2014. 1 changed file with 0 additions and 3 deletions.
    3 changes: 0 additions & 3 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -1,3 +0,0 @@
    I'm Reto Meier -- I've been a developer advocate for Android at Google for 5 years. I started working on Android so long ago, that back then there *were* no devices. All you had to work with were an emulator, a BETA SDK and an almost fanatical devotion to the platform.

    I’ll be joining you from here -- my underground Android Developer Bunker -- and my goal isn't to get you up and running as quickly as possible -- it's to teach you the context behind the choices we’ll make, and the best practices you need to really understand how to create great experiences specifically tailored to mobile devices. By the time you finish this course, you'll know more than just how to create yet-another-app; you’ll know how to build great apps, that focus on the user.
  2. jwill revised this gist Jun 12, 2014. 1 changed file with 2 additions and 7 deletions.
    9 changes: 2 additions & 7 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -1,8 +1,3 @@
    I'm Reto Meier -- I've been a developer advocate for Android at Google for 5 years. I started working on Android so long ago, that back then there *were* no devices. All you had to work with were an emulator, a BETA SDK and an almost fanatical devotion to the platform.

    The final step in your Custom View creation is adding interactivity. You can listen for user input events including [draw] keypresses
    [draw] Trackball movement, and
    most importantly [draw] screen touch events, by overriding the corresponding event handlers.
    Android supports tracking of up to 11 individual contact points in what we like to call “Jazz Hands” mode -- enabling you to create complex multi-finger interaction models.
    There’s really no interaction required for a wind gauge, but you can find out more about handling Input events by checking the MotionEvent docs, or the developer guide on creating your own fully interactive custom views in the Instructor Notes below.
    Now be careful not to let this new found power go to your head. By definition, your users will never have encountered your brand-spanking new control -- so learning how to use it will add friction to their use of your app. At the very least, it should behave consistently with the rest of the system, and you should avoid creating your own versions of system controls. If it look kinda-like a button, and works kinda-like a button. You should probably just go ahead and use a button.
    But I think this non-sequitur has gone on long enough -- and it’s time to get back to our weather app.
    I’ll be joining you from here -- my underground Android Developer Bunker -- and my goal isn't to get you up and running as quickly as possible -- it's to teach you the context behind the choices we’ll make, and the best practices you need to really understand how to create great experiences specifically tailored to mobile devices. By the time you finish this course, you'll know more than just how to create yet-another-app; you’ll know how to build great apps, that focus on the user.
  3. jwill revised this gist Jun 12, 2014. 1 changed file with 7 additions and 6 deletions.
    13 changes: 7 additions & 6 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -1,7 +1,8 @@

    That looks pretty sweet -- but what about users who can’t see your shiny new control? Accessibility is a key consideration when building apps, and particularly when creating new Views.
    You can start by adding a contentDescription[draw] as you would for every other View in your layout.
    But what about Views like our wind speed & direction gauge -- where the content isn’t static. Knowing you’re looking at a wind gauge isn’t very useful if we don’t know what what the speed and direction it’s displaying is.
    Well within your control, send an accessibility event[draw] whenever the visual content has been modified.
    Then override the dispatchPopulateAccessibilityEvent handler [draw] adding the current control’s visual value to the accessibiliy event
    Add accessibility handlers to your View -- in XML, and within the View if appropriate, and click here when you’re done.
    The final step in your Custom View creation is adding interactivity. You can listen for user input events including [draw] keypresses
    [draw] Trackball movement, and
    most importantly [draw] screen touch events, by overriding the corresponding event handlers.
    Android supports tracking of up to 11 individual contact points in what we like to call “Jazz Hands” mode -- enabling you to create complex multi-finger interaction models.
    There’s really no interaction required for a wind gauge, but you can find out more about handling Input events by checking the MotionEvent docs, or the developer guide on creating your own fully interactive custom views in the Instructor Notes below.
    Now be careful not to let this new found power go to your head. By definition, your users will never have encountered your brand-spanking new control -- so learning how to use it will add friction to their use of your app. At the very least, it should behave consistently with the rest of the system, and you should avoid creating your own versions of system controls. If it look kinda-like a button, and works kinda-like a button. You should probably just go ahead and use a button.
    But I think this non-sequitur has gone on long enough -- and it’s time to get back to our weather app.
  4. jwill revised this gist Jun 12, 2014. 1 changed file with 2 additions and 11 deletions.
    13 changes: 2 additions & 11 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -3,14 +3,5 @@ That looks pretty sweet -- but what about users who can’t see your shiny new c
    You can start by adding a contentDescription[draw] as you would for every other View in your layout.
    But what about Views like our wind speed & direction gauge -- where the content isn’t static. Knowing you’re looking at a wind gauge isn’t very useful if we don’t know what what the speed and direction it’s displaying is.
    Well within your control, send an accessibility event[draw] whenever the visual content has been modified.
    Then override the dispatchPopulateAccessibilityEvent handler [draw] adding the current control’s visual value to the accessibility event


    onMeasure is called when your View’s parent is laying out it’s children. As you know, when you add a View to a layout, you can specify a specific height or width -- but in most cases you’ll want to match parent or wrap the content.
    When a Views’s onMeasure is called by it’s parent layout, it asks: “How much space will you use?”
    ...And passes in how much space is available, and whether the View will be given exactly that much space, or at most that much space.
    You can decode that like this: [Draw] to obtain the size and mode parameter for the height and width bounds respectively.
    If the returned mode is exactly [draw], the View will be placed into an area of exactly that size. You’ll be passed that value if the layout has specified a specific size, or if the View has been asked to fill the parent. In either case, it’s best practice to simply return the value passed in, unless that value is below your View’s minimum size -- in which case you can return the minimum value and rely on the parent Layout to crop or scroll as necessary.
    The other alternative is AT_MOST, indicating that your view can define it’s own size, up to the size given. This is typically the case for Views set to WRAP_CONTENT -- where the View should be as wide as it needs to be to display it’s content (but no wider!), all provided it still fits within the parent container.
    Once you’ve determined the size of your control, you *must* call setMeasuredDimension -- passing in your values. If you don’t -- your app will crash as soon as your View is laid out.

    Then override the dispatchPopulateAccessibilityEvent handler [draw] adding the current control’s visual value to the accessibiliy event
    Add accessibility handlers to your View -- in XML, and within the View if appropriate, and click here when you’re done.
  5. jwill revised this gist Jun 12, 2014. 1 changed file with 5 additions and 10 deletions.
    15 changes: 5 additions & 10 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -1,15 +1,10 @@

    That looks pretty sweet -- but what about users who can’t see your shiny new control? Accessibility is a key consideration when building apps, and particularly when creating new Views.
    You can start by adding a contentDescription[draw] as you would for every other View in your layout.
    But what about Views like our wind speed & direction gauge -- where the content isn’t static. Knowing you’re looking at a wind gauge isn’t very useful if we don’t know what what the speed and direction it’s displaying is.
    Well within your control, send an accessibility event[draw] whenever the visual content has been modified.
    Then override the dispatchPopulateAccessibilityEvent handler [draw] adding the current control’s visual value to the accessibility event

    Knowing the standard widget library is nice, but as someone who was once accused as not so much recreating the wheel as hand machining my own nuts and bolts -- I know there are times when nothing in the toolchest will quite do the job. That’s when it’s time to dive in and build your own custom View from scratch.
    We’re not including any custom Views in sunshine, but let’s take a look at how you *would* build one.
    You start by creating a new Class for your view [draw]
    If you’re building something from scratch rather than modifying an existing View, it should descend from either View itself [Draw]...or SurfaceView [Draw]
    View offers a lightweight canvas-based approach, while SurfaceView is designed specifically to support UI elements that require rapid redraws and / or 3D graphics using something like openGL. It’s perfect for Views that display games or Videos.
    The existing widget library Views are descended from View, so let’s take that approach [Circle View].
    The base View class draws [Draw] an empty, borderless 100x100 pixel box.
    To change that we override the onMeasure handler [draw] to indicate the View’s size,
    and onDraw [draw] to draw its content.
    If your View should always be an empty 100 pixel square, you’re in luck! Otherwise, we need to do some work. Let’s start by setting its size.

    onMeasure is called when your View’s parent is laying out it’s children. As you know, when you add a View to a layout, you can specify a specific height or width -- but in most cases you’ll want to match parent or wrap the content.
    When a Views’s onMeasure is called by it’s parent layout, it asks: “How much space will you use?”
  6. jwill revised this gist Jun 12, 2014. 1 changed file with 4 additions and 1 deletion.
    5 changes: 4 additions & 1 deletion gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,5 @@


    Knowing the standard widget library is nice, but as someone who was once accused as not so much recreating the wheel as hand machining my own nuts and bolts -- I know there are times when nothing in the toolchest will quite do the job. That’s when it’s time to dive in and build your own custom View from scratch.
    We’re not including any custom Views in sunshine, but let’s take a look at how you *would* build one.
    You start by creating a new Class for your view [draw]
    @@ -15,4 +17,5 @@ When a Views’s onMeasure is called by it’s parent layout, it asks: “How mu
    You can decode that like this: [Draw] to obtain the size and mode parameter for the height and width bounds respectively.
    If the returned mode is exactly [draw], the View will be placed into an area of exactly that size. You’ll be passed that value if the layout has specified a specific size, or if the View has been asked to fill the parent. In either case, it’s best practice to simply return the value passed in, unless that value is below your View’s minimum size -- in which case you can return the minimum value and rely on the parent Layout to crop or scroll as necessary.
    The other alternative is AT_MOST, indicating that your view can define it’s own size, up to the size given. This is typically the case for Views set to WRAP_CONTENT -- where the View should be as wide as it needs to be to display it’s content (but no wider!), all provided it still fits within the parent container.
    Once you’ve determined the size of your control, you *must* call setMeasuredDimension -- passing in your values. If you don’t -- your app will crash as soon as your View is laid out.
    Once you’ve determined the size of your control, you *must* call setMeasuredDimension -- passing in your values. If you don’t -- your app will crash as soon as your View is laid out.

  7. jwill revised this gist Jun 12, 2014. 1 changed file with 8 additions and 1 deletion.
    9 changes: 8 additions & 1 deletion gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,3 @@

    Knowing the standard widget library is nice, but as someone who was once accused as not so much recreating the wheel as hand machining my own nuts and bolts -- I know there are times when nothing in the toolchest will quite do the job. That’s when it’s time to dive in and build your own custom View from scratch.
    We’re not including any custom Views in sunshine, but let’s take a look at how you *would* build one.
    You start by creating a new Class for your view [draw]
    @@ -9,3 +8,11 @@ The base View class draws [Draw] an empty, borderless 100x100 pixel box.
    To change that we override the onMeasure handler [draw] to indicate the View’s size,
    and onDraw [draw] to draw its content.
    If your View should always be an empty 100 pixel square, you’re in luck! Otherwise, we need to do some work. Let’s start by setting its size.

    onMeasure is called when your View’s parent is laying out it’s children. As you know, when you add a View to a layout, you can specify a specific height or width -- but in most cases you’ll want to match parent or wrap the content.
    When a Views’s onMeasure is called by it’s parent layout, it asks: “How much space will you use?”
    ...And passes in how much space is available, and whether the View will be given exactly that much space, or at most that much space.
    You can decode that like this: [Draw] to obtain the size and mode parameter for the height and width bounds respectively.
    If the returned mode is exactly [draw], the View will be placed into an area of exactly that size. You’ll be passed that value if the layout has specified a specific size, or if the View has been asked to fill the parent. In either case, it’s best practice to simply return the value passed in, unless that value is below your View’s minimum size -- in which case you can return the minimum value and rely on the parent Layout to crop or scroll as necessary.
    The other alternative is AT_MOST, indicating that your view can define it’s own size, up to the size given. This is typically the case for Views set to WRAP_CONTENT -- where the View should be as wide as it needs to be to display it’s content (but no wider!), all provided it still fits within the parent container.
    Once you’ve determined the size of your control, you *must* call setMeasuredDimension -- passing in your values. If you don’t -- your app will crash as soon as your View is laid out.
  8. jwill revised this gist Jun 12, 2014. 1 changed file with 10 additions and 12 deletions.
    22 changes: 10 additions & 12 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -1,13 +1,11 @@

    So if we treat Fragments as mini-Activities, each with its own independent lifecycle and UI, how does that compare to the lifecycle of a real Activity?
    As you might expect, the basic lifecycle events are the same -- and as the parent Activity moves through the cycle of starts and resumes, pauses and stops, those same lifecycle events will be triggered in the Fragment.
    So in most, cases you can simply move what you’d have put in an Activity’s lifecycle handlers into the corresponding Fragment handlers.
    With, of course, a couple of exceptions. Rather than building your UI here in onCreate, Fragments introduced a new event specifically for this [Draw]
    onCreateView is where you construct or inflate your UI, hook it up to any data sources, and return it to the parent Activity to integrate into its View hierarchy.
    There’s a corresponding onDestroyView handler [draw]. Which is called immediately before the Fragment is added to the backstack, independent of the parent activity.
    Keep in mind that that the Fragment Manager can add any Fragment Transactions -- adding, removing, or replacing Fragments -- to the backstack while a single parent Activity is active, so a Fragment can move through this cycle [gesture] multiple times indepdenent of the host Activity -- so onDestroyView is where you should clean up any resources related specifically to the UI -- such as bitmaps in memory, or cursors to data. That will help ensure your app’s memory footprint isn’t bloated by data that’s not needed when the Fragment isn’t visible.
    As soon as the Fragment is returned from the backstack, onCreateView [gesture] is called, and you can recreate the UI, and reconnect data sources, before your Fragment transitions through the rest of the lifecycle to become active again.
    Because a Fragment can only exist within an Activity, we also need callbacks to tell us when a Fragment is attached and detached from it’s parent [draw]
    onAttach is your opportunity to get a reference to the parent Activity, while onDetach is the last thing that happens -- even after your Fragment has technically been “destroyed”.
    The final piece of the puzzle is onActivityCreated [draw]. This notifies our Fragment that the parent Activity has completed its onCreate handler, and represents the point at which we can safely interact with its UI -- potentially including other Fragments.
    Just like the Activity Lifecycle we discussed in Lesson 3, once the Fragment is no longer visible [gesture], there’s a chance it will be terminated with no further code being executed. That can happen after onStop in the case of the Activity being terminated while the Fragment is part of the Activity, or after onDestroyView if the Fragment has been placed on the backstack when the Activity is destroyed.
    Knowing the standard widget library is nice, but as someone who was once accused as not so much recreating the wheel as hand machining my own nuts and bolts -- I know there are times when nothing in the toolchest will quite do the job. That’s when it’s time to dive in and build your own custom View from scratch.
    We’re not including any custom Views in sunshine, but let’s take a look at how you *would* build one.
    You start by creating a new Class for your view [draw]
    If you’re building something from scratch rather than modifying an existing View, it should descend from either View itself [Draw]...or SurfaceView [Draw]
    View offers a lightweight canvas-based approach, while SurfaceView is designed specifically to support UI elements that require rapid redraws and / or 3D graphics using something like openGL. It’s perfect for Views that display games or Videos.
    The existing widget library Views are descended from View, so let’s take that approach [Circle View].
    The base View class draws [Draw] an empty, borderless 100x100 pixel box.
    To change that we override the onMeasure handler [draw] to indicate the View’s size,
    and onDraw [draw] to draw its content.
    If your View should always be an empty 100 pixel square, you’re in luck! Otherwise, we need to do some work. Let’s start by setting its size.
  9. jwill revised this gist Jun 12, 2014. 1 changed file with 12 additions and 13 deletions.
    25 changes: 12 additions & 13 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -1,14 +1,13 @@

    So now you know where Fragments are used, and where we’re going to use them in our app -- you’re probably starting to ask, why use Fragments at all? If we want to group UI components couldn’t we just use a Viewgroup or create a reusable XML layout definition?


    Yes -- *but* the real power in Fragments goes beyond grouping UI elements - they allow us to fully modularize our Activities -- including [draw] the lifecycle events they receive and [draw] the app state they maintain.
    Fragments were first introduced in Honeycomb to solve a particular problem. Honeycomb was the first Android release to support tablet -- and it turned out the best way for most apps to create a great tablet UI was to put two (or more) of their phone Activities alongside each other.
    For example, if you had a phone app that started with a List Activity [Draw], which when you clicked an item would open a detail Activity [Draw] in what we refer to as the master-detail flow.
    A good tablet UI would put them side-by-side [Draw] like this. Functionally, clicking an item on the list now replaces the “Activity” on the right rather than starting a new one as it would have on a phone.
    Unfortunately, Android didn’t support embedding Activities within other Activities. Or at least it *didn’t* -- until we introduced Fragments.
    If you just look at the UI elements, you could be excused for thinking you could achieve the same thing using an Activity, one that built the same UI using View Groups and layouts without bothering with Fragments, which is true. Up to a point. But you’d then have to pass through all the Activity lifecycle events, manage the state of each peice of the UI, keep track of the state of each portion as it changed, and remember which screen elements were on screen at any time to maintain app state.
    All of which is exactly what the Fragment Manager does for you when you use Fragments -- allowing you to take a step back and treat each Fragment as though it were a mini-Activity.
    For example, in the world of Activities, you start one Activity from another and the transaction is recorded on the back stack, hitting the “back” button, undoes the transaction and returns to the previous Activity.
    The same thing happens with fragment transactions -- rather than starting a new Activity, we could replace the List Fragment with the Detail Fragment, with the back button switching them back.
    So in theory, you could take all apps with multiple Activities and replace them with a single Activity with multiple Fragments.
    So if we treat Fragments as mini-Activities, each with its own independent lifecycle and UI, how does that compare to the lifecycle of a real Activity?
    As you might expect, the basic lifecycle events are the same -- and as the parent Activity moves through the cycle of starts and resumes, pauses and stops, those same lifecycle events will be triggered in the Fragment.
    So in most, cases you can simply move what you’d have put in an Activity’s lifecycle handlers into the corresponding Fragment handlers.
    With, of course, a couple of exceptions. Rather than building your UI here in onCreate, Fragments introduced a new event specifically for this [Draw]
    onCreateView is where you construct or inflate your UI, hook it up to any data sources, and return it to the parent Activity to integrate into its View hierarchy.
    There’s a corresponding onDestroyView handler [draw]. Which is called immediately before the Fragment is added to the backstack, independent of the parent activity.
    Keep in mind that that the Fragment Manager can add any Fragment Transactions -- adding, removing, or replacing Fragments -- to the backstack while a single parent Activity is active, so a Fragment can move through this cycle [gesture] multiple times indepdenent of the host Activity -- so onDestroyView is where you should clean up any resources related specifically to the UI -- such as bitmaps in memory, or cursors to data. That will help ensure your app’s memory footprint isn’t bloated by data that’s not needed when the Fragment isn’t visible.
    As soon as the Fragment is returned from the backstack, onCreateView [gesture] is called, and you can recreate the UI, and reconnect data sources, before your Fragment transitions through the rest of the lifecycle to become active again.
    Because a Fragment can only exist within an Activity, we also need callbacks to tell us when a Fragment is attached and detached from it’s parent [draw]
    onAttach is your opportunity to get a reference to the parent Activity, while onDetach is the last thing that happens -- even after your Fragment has technically been “destroyed”.
    The final piece of the puzzle is onActivityCreated [draw]. This notifies our Fragment that the parent Activity has completed its onCreate handler, and represents the point at which we can safely interact with its UI -- potentially including other Fragments.
    Just like the Activity Lifecycle we discussed in Lesson 3, once the Fragment is no longer visible [gesture], there’s a chance it will be terminated with no further code being executed. That can happen after onStop in the case of the Activity being terminated while the Fragment is part of the Activity, or after onDestroyView if the Fragment has been placed on the backstack when the Activity is destroyed.
  10. jwill revised this gist Jun 12, 2014. 1 changed file with 13 additions and 17 deletions.
    30 changes: 13 additions & 17 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -1,18 +1,14 @@

    It looks like we’re about to start implementing our tablet design, so now’s a great time to introduce you to the Android resource framework.
    All externalized Android resources -- everything from strings, to layouts, to drawables, and animations are stored within your projects [draw] res folder.
    You’ve already been putting your strings in the strings xml file stored in the [draw] values folder, and your layouts in the [draw] layout folder.
    You reference your resources using the @ notation within your XML or in code, then at run time Android inserts the appropriate resource.
    So far so good -- and here’s where things get interesting.
    Android allows you to create alternative versions of every resource, by placing them into folders with different qualifiers - separated with a hyphen - based on anything from [draw] language and / or dialect, to...
    [draw] whether the device is docked,
    [draw] the type of touch screen,
    [draw] the pixel density of the display,
    [draw] the screen orientation, and most importantly for responsive design...
    [draw] the smallest available screen width.
    At runtime, Android will check the current device configuration, language, screen size, and pixel density and load the right layouts, strings, and drawables.
    You can chain these qualifiers together, for example to create a different layout for German language users to account for their long words -- or more typically, for a combination of screen size and device configuration.
    Keep in mind that many of these values can change at runtime -- the most common change being orientation. It’s for this reason that Android activities are destroyed and recreated whenever the device configuration changes -- as the layout, and all the resources within it, could be completely different based on a simple rotation.
    It’s good practice to localize your apps and provide translated strings for all users -- a task made easier thanks to the Google Play publisher site that can offer that service.
    It’s also a good idea to provide different drawables at the appropriate pixel density, so you get nice crisp images on every device.
    When it comes to providing alternative layouts, Android has gone through a few alternative models -- starting with screen “buckets” of small, normal, large, and extra large -- but since Android 3.2 the new smallest width qualifier has given us more fine grained control over our layouts.
    So now you know where Fragments are used, and where we’re going to use them in our app -- you’re probably starting to ask, why use Fragments at all? If we want to group UI components couldn’t we just use a Viewgroup or create a reusable XML layout definition?


    Yes -- *but* the real power in Fragments goes beyond grouping UI elements - they allow us to fully modularize our Activities -- including [draw] the lifecycle events they receive and [draw] the app state they maintain.
    Fragments were first introduced in Honeycomb to solve a particular problem. Honeycomb was the first Android release to support tablet -- and it turned out the best way for most apps to create a great tablet UI was to put two (or more) of their phone Activities alongside each other.
    For example, if you had a phone app that started with a List Activity [Draw], which when you clicked an item would open a detail Activity [Draw] in what we refer to as the master-detail flow.
    A good tablet UI would put them side-by-side [Draw] like this. Functionally, clicking an item on the list now replaces the “Activity” on the right rather than starting a new one as it would have on a phone.
    Unfortunately, Android didn’t support embedding Activities within other Activities. Or at least it *didn’t* -- until we introduced Fragments.
    If you just look at the UI elements, you could be excused for thinking you could achieve the same thing using an Activity, one that built the same UI using View Groups and layouts without bothering with Fragments, which is true. Up to a point. But you’d then have to pass through all the Activity lifecycle events, manage the state of each peice of the UI, keep track of the state of each portion as it changed, and remember which screen elements were on screen at any time to maintain app state.
    All of which is exactly what the Fragment Manager does for you when you use Fragments -- allowing you to take a step back and treat each Fragment as though it were a mini-Activity.
    For example, in the world of Activities, you start one Activity from another and the transaction is recorded on the back stack, hitting the “back” button, undoes the transaction and returns to the previous Activity.
    The same thing happens with fragment transactions -- rather than starting a new Activity, we could replace the List Fragment with the Detail Fragment, with the back button switching them back.
    So in theory, you could take all apps with multiple Activities and replace them with a single Activity with multiple Fragments.
  11. jwill revised this gist Jun 12, 2014. 1 changed file with 18 additions and 1 deletion.
    19 changes: 18 additions & 1 deletion gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -1 +1,18 @@
    Blah

    It looks like we’re about to start implementing our tablet design, so now’s a great time to introduce you to the Android resource framework.
    All externalized Android resources -- everything from strings, to layouts, to drawables, and animations are stored within your projects [draw] res folder.
    You’ve already been putting your strings in the strings xml file stored in the [draw] values folder, and your layouts in the [draw] layout folder.
    You reference your resources using the @ notation within your XML or in code, then at run time Android inserts the appropriate resource.
    So far so good -- and here’s where things get interesting.
    Android allows you to create alternative versions of every resource, by placing them into folders with different qualifiers - separated with a hyphen - based on anything from [draw] language and / or dialect, to...
    [draw] whether the device is docked,
    [draw] the type of touch screen,
    [draw] the pixel density of the display,
    [draw] the screen orientation, and most importantly for responsive design...
    [draw] the smallest available screen width.
    At runtime, Android will check the current device configuration, language, screen size, and pixel density and load the right layouts, strings, and drawables.
    You can chain these qualifiers together, for example to create a different layout for German language users to account for their long words -- or more typically, for a combination of screen size and device configuration.
    Keep in mind that many of these values can change at runtime -- the most common change being orientation. It’s for this reason that Android activities are destroyed and recreated whenever the device configuration changes -- as the layout, and all the resources within it, could be completely different based on a simple rotation.
    It’s good practice to localize your apps and provide translated strings for all users -- a task made easier thanks to the Google Play publisher site that can offer that service.
    It’s also a good idea to provide different drawables at the appropriate pixel density, so you get nice crisp images on every device.
    When it comes to providing alternative layouts, Android has gone through a few alternative models -- starting with screen “buckets” of small, normal, large, and extra large -- but since Android 3.2 the new smallest width qualifier has given us more fine grained control over our layouts.
  12. jwill revised this gist Jun 4, 2014. 1 changed file with 1 addition and 2 deletions.
    3 changes: 1 addition & 2 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -1,2 +1 @@
    [Shot C] So, just like desktop or web - where you might use panels or CSS, your Android UI needs to scale based on the screen it’s running within.
    Which is why AbsoluteLayout was deprecated [Write out the three][Shot B] in favor of Layouts like linear layout, relative layout and grid layout -- [Shot A] that can dynamically resize and adapt to any screen, following the principles of responsive design.
    Blah
  13. jwill revised this gist Jun 4, 2014. 1 changed file with 2 additions and 3 deletions.
    5 changes: 2 additions & 3 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,2 @@
    [Shot A] Now it’s important to remember that we’re not here to teach you how to build a weather app. It’s not even to teach you all the Android APIs that we’ll use to build it. It’s really about re-training your brain to start thinking like a mobile developer. Which is really important because at the end of this course we’re going to ask you to build your own final project.
    [Shot B] We’re expecting you to already be familiar with object oriented programming, and have experience with Java, or a similar language -- personally I got started with Android after years of Delphi and C# .NET development.
    [Shot C] As engineers, we’re trained to map our experience in one language or SDK into new ones -- looking for patterns and shortcuts so we can get up to speed as quickly as possible. But mobile - and Android in particular - has some fundamental differences that mean some of our experience and intuition will make you a worse mobile engineer.
    [Shot C] So, just like desktop or web - where you might use panels or CSS, your Android UI needs to scale based on the screen it’s running within.
    Which is why AbsoluteLayout was deprecated [Write out the three][Shot B] in favor of Layouts like linear layout, relative layout and grid layout -- [Shot A] that can dynamically resize and adapt to any screen, following the principles of responsive design.
  14. jwill revised this gist Jun 4, 2014. 1 changed file with 3 additions and 8 deletions.
    11 changes: 3 additions & 8 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -1,8 +1,3 @@
    Ok. So before Dan gets carried away with databases, let’s look at what happens when you use an Intent to transition between Activities.
    Within Sunshine, if you tap on a list item in the MainActivity, it opens up the DetailActivity - but the MainActivity remains on the backstack, ready to reappear as soon as you hit back.
    Now in that example, both Activities are within the same App, but as we learned in Lesson 3, you can also launch the browser or a maps app from Sunshine.
    Or, for that matter, the user can hit home, or use the recent apps key to switch to another app -- or open a notification -- anything.
    Keep in mind that resources on our devices are extremely limited, so it’s not a good idea to have dozens of apps sitting idle in the background. Android solves this for us, so you don’t have to use those awful task-killer apps.
    So how does it do that? Well, it kills low priority applications that you haven’t used in a while.
    We’ll go into detail on exactly how it figures out which app needs to die in Lesson 6, but for now, it’s important to realize that your app isn’t in control of its own destiny -- they can be killed at any time [topple easel] -- so you need to know how to deal with that.
    And that means understanding the lifecycle of an Activity, and the signals we get from the framework to indicate its progress through it’s lifetime.
    [Shot A] Now it’s important to remember that we’re not here to teach you how to build a weather app. It’s not even to teach you all the Android APIs that we’ll use to build it. It’s really about re-training your brain to start thinking like a mobile developer. Which is really important because at the end of this course we’re going to ask you to build your own final project.
    [Shot B] We’re expecting you to already be familiar with object oriented programming, and have experience with Java, or a similar language -- personally I got started with Android after years of Delphi and C# .NET development.
    [Shot C] As engineers, we’re trained to map our experience in one language or SDK into new ones -- looking for patterns and shortcuts so we can get up to speed as quickly as possible. But mobile - and Android in particular - has some fundamental differences that mean some of our experience and intuition will make you a worse mobile engineer.
  15. jwill revised this gist Jun 4, 2014. 1 changed file with 8 additions and 3 deletions.
    11 changes: 8 additions & 3 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,8 @@


    [Draw line] Since Honeycomb, Android apps can rely on onStop being called before the app is at risk of being terminated, but if you’re supporting pre Honeycomb devices you should prepare for termination as early as after onPause. Let’s take a closer look at how you should prepare for an untimely app death.
    Ok. So before Dan gets carried away with databases, let’s look at what happens when you use an Intent to transition between Activities.
    Within Sunshine, if you tap on a list item in the MainActivity, it opens up the DetailActivity - but the MainActivity remains on the backstack, ready to reappear as soon as you hit back.
    Now in that example, both Activities are within the same App, but as we learned in Lesson 3, you can also launch the browser or a maps app from Sunshine.
    Or, for that matter, the user can hit home, or use the recent apps key to switch to another app -- or open a notification -- anything.
    Keep in mind that resources on our devices are extremely limited, so it’s not a good idea to have dozens of apps sitting idle in the background. Android solves this for us, so you don’t have to use those awful task-killer apps.
    So how does it do that? Well, it kills low priority applications that you haven’t used in a while.
    We’ll go into detail on exactly how it figures out which app needs to die in Lesson 6, but for now, it’s important to realize that your app isn’t in control of its own destiny -- they can be killed at any time [topple easel] -- so you need to know how to deal with that.
    And that means understanding the lifecycle of an Activity, and the signals we get from the framework to indicate its progress through it’s lifetime.
  16. jwill revised this gist Jun 4, 2014. 1 changed file with 3 additions and 8 deletions.
    11 changes: 3 additions & 8 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -1,8 +1,3 @@
    [Shot C] The Active lifecycle is when your Activity is in the foreground and has focus. It’s actively receiving input from user events and no other Activities are obscuring it. onPause is called, and the Active lifetime ends, as soon as your Activity is partially obscured -- for example when a dialog is displayed above it for an in-app purchase, or to select another Activity to fulfill an implicit Intent.
    To make efficient use of limited resources, you’ll want to use these signals to adjust your app’s resource burden.
    So most updates to your UI can be paused when this lifetime ends -- announced by onPause -- but it is still visible, so you shouldn’t pause any processes that are drawing your UI.
    The visible lifetime on the other hand, continues whenever the app is at all visible, and ends as soon as it’s completely obscured by another app, and it moves to the background. When you see onStop you know the user can’t see your app at all.
    All of which is to say that while onCreate and onDestroy will be called at most once each time your app is run - onStart and onResume (and onPause and onStop) will likely be called many times while the app is running.
    Now, this is where things get a little different. On almost all platforms, app lifecycles are deterministic. Generally you’ll start a program, and it’ll keep running until it either completes or the user cancels it.
    If you look at traditional desktop development, that means your app keeps running until your user chooses “quit” or “exit” from the file menu, at which point you can save state and free resources.
    But as we know, on Android lifecycles work a little differently. So let’s take a closer look at how.


    [Draw line] Since Honeycomb, Android apps can rely on onStop being called before the app is at risk of being terminated, but if you’re supporting pre Honeycomb devices you should prepare for termination as early as after onPause. Let’s take a closer look at how you should prepare for an untimely app death.
  17. jwill revised this gist Jun 4, 2014. 1 changed file with 8 additions and 8 deletions.
    16 changes: 8 additions & 8 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -1,8 +1,8 @@
    [Shot A] A platform which terminates apps on its own is a pretty radical departure for anyone like me who cut their teeth on desktop Winforms development.
    If you come from a similar background, you probably have a good idea of what you to expect in terms of lifecyle event handlers.
    [draw] [Shot B] Our app has a main form - or Activity - [Shot A] that’s launched when the app is opened.
    [draw build up] [Shot B] Then you listen for the onCreate callback to inflate your XML layout into the Activity’s UI and wire it up. At this point the Activity has been created.
    [Shot A] It likely won’t be a surprise to you that there is a handler for when the Activity becomes visible. onStart, and another for when it has focus as the active foreground app, this one is onResume.
    [draw teardown] [Shot B] And that the same is true in reverse, with onPause indicating the Activity has lost focus and should be paused, and onStop indicating that the app is no longer visible and should be stopped.
    [Shot A] Finally, there’s an onDestroy method that’s fired [draw the next part] [Shot B] just before the Activity is destroyed.
    [Shot A] When your app is first launched, you’ll quickly move through these states -- create, start, resume -- one after the other. But within the full application lifetime: from when onCreate is first called until the application is terminated -- your app will move through the active [indicate] and visible [indicate] lifecycles many times.
    [Shot C] The Active lifecycle is when your Activity is in the foreground and has focus. It’s actively receiving input from user events and no other Activities are obscuring it. onPause is called, and the Active lifetime ends, as soon as your Activity is partially obscured -- for example when a dialog is displayed above it for an in-app purchase, or to select another Activity to fulfill an implicit Intent.
    To make efficient use of limited resources, you’ll want to use these signals to adjust your app’s resource burden.
    So most updates to your UI can be paused when this lifetime ends -- announced by onPause -- but it is still visible, so you shouldn’t pause any processes that are drawing your UI.
    The visible lifetime on the other hand, continues whenever the app is at all visible, and ends as soon as it’s completely obscured by another app, and it moves to the background. When you see onStop you know the user can’t see your app at all.
    All of which is to say that while onCreate and onDestroy will be called at most once each time your app is run - onStart and onResume (and onPause and onStop) will likely be called many times while the app is running.
    Now, this is where things get a little different. On almost all platforms, app lifecycles are deterministic. Generally you’ll start a program, and it’ll keep running until it either completes or the user cancels it.
    If you look at traditional desktop development, that means your app keeps running until your user chooses “quit” or “exit” from the file menu, at which point you can save state and free resources.
    But as we know, on Android lifecycles work a little differently. So let’s take a closer look at how.
  18. jwill revised this gist Jun 4, 2014. 1 changed file with 8 additions and 4 deletions.
    12 changes: 8 additions & 4 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,8 @@
    As you were moving around between apps, you probably noticed that from a *user* perspective, Android doesn’t announce changes in app state, it doesn’t announce that it’s low in memory, or ask users to close apps to free up resources. In fact, it does everything it can to make the resource limitations of the device invisible to the user.
    That means keeping the foreground app running smoothly, and switching between apps seamless -- and that means killing apps in the background (remove background app layers) if it needs their resources to make that happen.
    So, we know that as soon as your app isn’t visible, it’s lifetime is as perilous as that of a Stark at the Red Wedding -- likely to die without notice (but ready to return from the dead). That tells us some very important things about how our apps should behave to be good citizens, and provide a great user experience.
    From a system perspective, onPause and onStop are signals that our app may be killed imminently, so we need to clean up any resources that need an orderly teardown -- such as closing any open connections or sockets.
    [Shot A] A platform which terminates apps on its own is a pretty radical departure for anyone like me who cut their teeth on desktop Winforms development.
    If you come from a similar background, you probably have a good idea of what you to expect in terms of lifecyle event handlers.
    [draw] [Shot B] Our app has a main form - or Activity - [Shot A] that’s launched when the app is opened.
    [draw build up] [Shot B] Then you listen for the onCreate callback to inflate your XML layout into the Activity’s UI and wire it up. At this point the Activity has been created.
    [Shot A] It likely won’t be a surprise to you that there is a handler for when the Activity becomes visible. onStart, and another for when it has focus as the active foreground app, this one is onResume.
    [draw teardown] [Shot B] And that the same is true in reverse, with onPause indicating the Activity has lost focus and should be paused, and onStop indicating that the app is no longer visible and should be stopped.
    [Shot A] Finally, there’s an onDestroy method that’s fired [draw the next part] [Shot B] just before the Activity is destroyed.
    [Shot A] When your app is first launched, you’ll quickly move through these states -- create, start, resume -- one after the other. But within the full application lifetime: from when onCreate is first called until the application is terminated -- your app will move through the active [indicate] and visible [indicate] lifecycles many times.
  19. jwill revised this gist Jun 4, 2014. 1 changed file with 4 additions and 6 deletions.
    10 changes: 4 additions & 6 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,4 @@
    [Shot A] As app developers, it’s our job to maintain the illusion that once started, every app is waiting patiently in the background, looking for it’s chance to be the star when called on.
    So whenever the user switches back to your app -- whether or not the system has killed it in the interim -- they should be presented with the same UI they had when they left.
    To help, Android has another pair of handlers specifically for persisting state in these circumstances.
    [Shot C] [Draw] onSaveInstanceState is called immediately before onPause -- so as soon as your app is no longer active -- And onRestoreInstanceState is called immediately after onCreate if the app is being started after having been terminated by the system.
    [Shot A] That means you can read the bundle of state information saved the last time your app was moved from the foreground here [point], the next time the user switches to your app -- even if it was killed by the system in the meantime. Using that bundle, you can return your UI to the same state it was the last time the user saw it, creating a seamless transition that hides the resource management happening under the covers.
    You’ll learn more about this, and get back to coding with Dan, next.
    As you were moving around between apps, you probably noticed that from a *user* perspective, Android doesn’t announce changes in app state, it doesn’t announce that it’s low in memory, or ask users to close apps to free up resources. In fact, it does everything it can to make the resource limitations of the device invisible to the user.
    That means keeping the foreground app running smoothly, and switching between apps seamless -- and that means killing apps in the background (remove background app layers) if it needs their resources to make that happen.
    So, we know that as soon as your app isn’t visible, it’s lifetime is as perilous as that of a Stark at the Red Wedding -- likely to die without notice (but ready to return from the dead). That tells us some very important things about how our apps should behave to be good citizens, and provide a great user experience.
    From a system perspective, onPause and onStop are signals that our app may be killed imminently, so we need to clean up any resources that need an orderly teardown -- such as closing any open connections or sockets.
  20. jwill revised this gist Jun 4, 2014. 1 changed file with 6 additions and 3 deletions.
    9 changes: 6 additions & 3 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,6 @@
    [Shot A] For the purposes of the Sunshine app, this information is purely theoretical. In fact, you’ll really only need to consider this later, when you're adding things like sensor or location listeners. Until then, the default components will handle much of this behaviour for you.
    [Shot B] In any case, now that you understand the lifecycle, and the way the system handles exiting your app when it requires the resources, you should hopefully understand why exit or “quit” buttons in Android apps serve no practical purpose. At most, you can call finish() on an Activity and it will get torn down instantly -- but that’s actually what happens when a user simply hits “back” from within an Activity.
    If you’re still not convinced, check out the video in the instructor notes where I explain my reasoning with a little more… color. [funny screenshot of video]
    [Shot A] As app developers, it’s our job to maintain the illusion that once started, every app is waiting patiently in the background, looking for it’s chance to be the star when called on.
    So whenever the user switches back to your app -- whether or not the system has killed it in the interim -- they should be presented with the same UI they had when they left.
    To help, Android has another pair of handlers specifically for persisting state in these circumstances.
    [Shot C] [Draw] onSaveInstanceState is called immediately before onPause -- so as soon as your app is no longer active -- And onRestoreInstanceState is called immediately after onCreate if the app is being started after having been terminated by the system.
    [Shot A] That means you can read the bundle of state information saved the last time your app was moved from the foreground here [point], the next time the user switches to your app -- even if it was killed by the system in the meantime. Using that bundle, you can return your UI to the same state it was the last time the user saw it, creating a seamless transition that hides the resource management happening under the covers.
    You’ll learn more about this, and get back to coding with Dan, next.
  21. jwill revised this gist Jun 4, 2014. 1 changed file with 3 additions and 3 deletions.
    6 changes: 3 additions & 3 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,3 @@
    [examples written] Some good examples you might have come up with are Sensor Listeners, Location updates, Realtime physics or lighting engines, and Programatically registered Broadcast Receivers.
    Anything that doesn’t need to keep updating until the user returns to the app should be paused on onPause and resumed in onResume. Anything that should keep happening when the Activity is paused, shouldn’t happen within an Activity -- and we’ll look at some of those in later lessons.
    Keep in mind that your Activity is still *visible* -- though partially obscured -- when it’s paused but not stopped. So don’t stop drawing your UI when you receive onPause!
    [Shot A] For the purposes of the Sunshine app, this information is purely theoretical. In fact, you’ll really only need to consider this later, when you're adding things like sensor or location listeners. Until then, the default components will handle much of this behaviour for you.
    [Shot B] In any case, now that you understand the lifecycle, and the way the system handles exiting your app when it requires the resources, you should hopefully understand why exit or “quit” buttons in Android apps serve no practical purpose. At most, you can call finish() on an Activity and it will get torn down instantly -- but that’s actually what happens when a user simply hits “back” from within an Activity.
    If you’re still not convinced, check out the video in the instructor notes where I explain my reasoning with a little more… color. [funny screenshot of video]
  22. jwill revised this gist Jun 4, 2014. 1 changed file with 3 additions and 3 deletions.
    6 changes: 3 additions & 3 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,3 @@


    It’s also a signal to our app that the system now considers it a low priority. Given the limited resources available, we should respond by reducing our use of system resources, particularly anything that could continue draining the battery. That includes anything that’s being used exclusively to update the UI: What are some examples of listeners or updates that should be paused or disconnected within onPause or onStop?
    [examples written] Some good examples you might have come up with are Sensor Listeners, Location updates, Realtime physics or lighting engines, and Programatically registered Broadcast Receivers.
    Anything that doesn’t need to keep updating until the user returns to the app should be paused on onPause and resumed in onResume. Anything that should keep happening when the Activity is paused, shouldn’t happen within an Activity -- and we’ll look at some of those in later lessons.
    Keep in mind that your Activity is still *visible* -- though partially obscured -- when it’s paused but not stopped. So don’t stop drawing your UI when you receive onPause!
  23. jwill revised this gist Jun 4, 2014. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -1 +1,3 @@


    It’s also a signal to our app that the system now considers it a low priority. Given the limited resources available, we should respond by reducing our use of system resources, particularly anything that could continue draining the battery. That includes anything that’s being used exclusively to update the UI: What are some examples of listeners or updates that should be paused or disconnected within onPause or onStop?
  24. jwill revised this gist Jun 4, 2014. 1 changed file with 1 addition and 2 deletions.
    3 changes: 1 addition & 2 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -1,2 +1 @@
    Let’s see if we can figure out what happens when our app is terminated in the background. Start the app again, then hit the home key.
    Now launch some other apps before returning to ours -- try and pick apps with large memory footprints. Can you figure out at which of the following lifecycle event handlers is the last one guaranteed to be called before your app can be terminated by the runtime?
    It’s also a signal to our app that the system now considers it a low priority. Given the limited resources available, we should respond by reducing our use of system resources, particularly anything that could continue draining the battery. That includes anything that’s being used exclusively to update the UI: What are some examples of listeners or updates that should be paused or disconnected within onPause or onStop?
  25. jwill revised this gist Jun 4, 2014. No changes.
  26. jwill revised this gist Jun 4, 2014. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -1,2 +1,2 @@
    So, why did this happen? As you’ll learn in Lesson 5, it’s possible to create different layouts and resources for different device configurations -- everything from screen size, to pixel density, and device orientation. Keep in mind that some of these values -- such as device orientation and screen width -- can change at runtime, so Android activities are destroyed and recreated whenever a device configuration changes -- because the layout, and all the resources within it, could be completely different based on something as simple as a screen rotation.
    And that’s not the only time your Activity might find itself unexpectedly being killed.
    Let’s see if we can figure out what happens when our app is terminated in the background. Start the app again, then hit the home key.
    Now launch some other apps before returning to ours -- try and pick apps with large memory footprints. Can you figure out at which of the following lifecycle event handlers is the last one guaranteed to be called before your app can be terminated by the runtime?
  27. jwill revised this gist Jun 4, 2014. 1 changed file with 2 additions and 3 deletions.
    5 changes: 2 additions & 3 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,2 @@
    You’ll notice that even changing the orientation of the device, will cause the Activity to be destroyed and recreated.
    Why did this happen?
    Share your ideas in the box provided.
    So, why did this happen? As you’ll learn in Lesson 5, it’s possible to create different layouts and resources for different device configurations -- everything from screen size, to pixel density, and device orientation. Keep in mind that some of these values -- such as device orientation and screen width -- can change at runtime, so Android activities are destroyed and recreated whenever a device configuration changes -- because the layout, and all the resources within it, could be completely different based on something as simple as a screen rotation.
    And that’s not the only time your Activity might find itself unexpectedly being killed.
  28. jwill revised this gist Jun 4, 2014. 1 changed file with 3 additions and 7 deletions.
    10 changes: 3 additions & 7 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -1,7 +1,3 @@
    [Written or write first] The correct order is
    onPause
    onStop
    onDestroy
    onCreate
    onStart
    onResume
    You’ll notice that even changing the orientation of the device, will cause the Activity to be destroyed and recreated.
    Why did this happen?
    Share your ideas in the box provided.
  29. jwill revised this gist Jun 4, 2014. 1 changed file with 7 additions and 4 deletions.
    11 changes: 7 additions & 4 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,7 @@


    Go ahead and add logging statements to the onPause, onResume, onStart, onStop, oncreate, and onResume Activity Lifecycle handlers. Start your app and try rotating your phone and observe the logs. What’s the sequence of lifecycle events your Activity goes through simply by changing the orientation?

    [Written or write first] The correct order is
    onPause
    onStop
    onDestroy
    onCreate
    onStart
    onResume
  30. jwill revised this gist Jun 4, 2014. 1 changed file with 4 additions and 1 deletion.
    5 changes: 4 additions & 1 deletion gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -1 +1,4 @@
    Go ahead and add logging statements to the onPause, onResume, onStart, onStop, oncreate, and onResume Activity Lifecycle handlers. Start your app and try rotating your phone and observe the logs. What’s the sequence of lifecycle events your Activity goes through simply by changing the orientation?


    Go ahead and add logging statements to the onPause, onResume, onStart, onStop, oncreate, and onResume Activity Lifecycle handlers. Start your app and try rotating your phone and observe the logs. What’s the sequence of lifecycle events your Activity goes through simply by changing the orientation?