Sunteți pe pagina 1din 131

Table

of Contents
1. Introduction
2. Android
i. History
ii. World Phone
iii. Ecosystem
iv. Design Considerations
v. Emerging Use Cases
3. TDD with Robolectric
i. Lab Background
ii. Lab: Robolectric Integration
iii. Lab: First Test
iv. What To Test
v. Best Practices
vi. Lab: Utility Functions
vii. Other Testing
4. Architecture
i. Android
ii. Model View Controller
iii. Building Blocks
iv. Message Passing
v. Threading Model
5. Fundamentals
i. Activities
ii. Manifest
iii. Layouts and Views
iv. View Groups
v. Fragments
vi. Lab: Design Chunking
i. Handout: Design Chunking
ii. Solution: Design Chunking
vii. Lab: Construct The View
i. Lab: Add DisplayFragment
ii. Lab: Add ButtonFragment
iii. Lab: Display View
iv. Lab: Add Buttons
viii. Application
ix. Lab: Add Application
x. Lab: Event Bus
6. Resource System
i. Design Principles
ii. Styles & Themes
iii. Dimensions & Colors
iv. Lab: View Styles
v. Qualifiers
vi. Lab: Flexible Dimensions
vii. Lab: Internationalization
viii. Drawables
ix. Lab: Button State
x. Lab: App Icon
7. Managing the Lifecycle
i. Application Lifecycle
ii. Activity Lifecycle

iii. Fragment Lifecycle


iv. Lab: Visualizing the Lifecycle
v. Backstack
vi. FragmentManager
vii. Lab: Add CalculatorFragment
viii. Instance State
8. Lab: Calculator
i. Lab: Requirements & Design
ii. Lab: User Interaction
iii. Lab: Getting On The Bus
iv. Lab: Testing
v. Lab: Routing Events
vi. Lab: Make It Work
vii. Lab: Device Rotation
9. Appendix
i. Tools
ii. Maven
iii. Resources
iv. IntelliJ Commands
10. Epilogue
11. About The Author
12. Bibliography

This workbook was originally created by Corey Leigh Latislaw as training materials for an in-person class.
This is free alpha version of this book, I hope you enjoy it! Join the mailing list to keep up with the official release.

What To Expect
Hands On
A portion of the day will be dedicated to lecture, but it's important to get you coding and exploring as soon as possible!
We will be working through a series of lab assignments as a complement to the material you will be learning. Our first
assignment will be creating a calculator application. This will cover several foundational Android topics. The second
assignment will be a regional food recommendation app where we'll cover networking, data management, and services.

Pair Programming
We'll be pair programming for the majority of the lab sessions. You are welcome to switch up pairs as often as you like, but
working solo isn't permitted. If we have an odd number of participants, I'll pair with someone in the class.
There are many pairing methodologies out there, but I generally favor ping ponging. In this model someone writes a failing
test (red) and then you switch who's in the driver's seat. The new developer makes the test pass (green) and refactors
(refactor) as necessary. Then they write a failing test and the cycle starts over again.
If you haven't pair programmed before, I think you'll like it. It can be quite fun and it's a great way to learn from others.

Chapter 1: Android
According to Meier, "mobile-phone ownership easily surpasses computer ownership [and] 2009 marked the year that more
people accessed the Internet for the first time from a mobile phone rather than a PC. Many people believe that within the
next 5 years more people will access the Internet by mobile phone rather than using personal computers."
Devices, such as phones and tablets, are quite literally changing the world one person and one app at a time.
Smartphones have become an indispensable part of our lives in the short time they have been around!
The potential you have to create a useful app for people the world over is a rare and special gift. It's hard to think of
something more rewarding to do in this world than to make such a personal connection and change the course of people's
lives. You can equip people with knowledge, tools, and games that will make them competitive in the years to come as
technology advances.
It's an exciting time to become and Android developer! There is a high demand and lots of opportunity to make an impact
locally and globally.
Knowing the foundations of Android will help you on your exploration of this fascinating platform to help you make apps that
can literally change the world!

Resources
Meier, Reto (2012-04-05). Professional Android 4 Application Development (Kindle Locations 499-502). John Wiley and
Sons. Kindle Edition.

History
A brief history of the Android world.
Global shipments have been rising at a fast pace. According to the IDC, last year alone it rose 23%. By 2018, there will be
an additional 1.8 billion devices in people's hands.

Of those phones, 80.2% will be Android!

References
Smartphone Momentum Still Evident with Shipments Expected to Reach 1.2 Billion in 2014 and Growing 23.1% Over
2013. May 28, 2014. Retrieved from http://www.idc.com/getdoc.jsp?containerId=prUS24857114.

World Phone
Android is so intriguing because it's a system that's accessible to the world over, not just the richest in our societies.
What makes Android so accessible is it's price. According to Sherman, it's on average less than half the price of an iOS
device.

As of January this year, we've reached a tipping point with a $50 phone, according to Oxford. This flings the doors wide to
developing nations and opens a new world of possibilities for apps. We can create meaningful experiences that will
transform the world. Phones are now half the price of an One Laptop Per Child laptop and arguably more powerful to
empower new people to join the global stage.
At Google I/O, they unveiled Android One. This system of partnerships between OEMs and Google will rapidly accelerate
adoption in emerging markets likely surpassing current projections. This project coupled with other initiatives to bring
faster Internet connections to the "dark" regions of the world will rapidly accelerate technology in those locations.
Emerging markets, such as China, Russia, and India are the fastest growing segment, which provides plenty of new use
cases and problems to solve.
"Shipments will more than double between now and 2018 within key emerging markets, including India, Indonesia,
and Russia. In addition, China will account for nearly a third of all smartphone shipments in 2018."
According to Oxford, "two-thirds of South Africans will have a mobile data subscription by 2017, more than doubling" the
current usage. Also, predictions estimate that "mobile data subscriptions in Nigeria and Kenya will rise from four percent" to
approximately 25%.
How can you best impact those markets?

References
Sherman, J. February 18, 2014. Retrieved from http://www.digitaltrends.com/mobile/android-way-cheaper-than-ios/.

Oxford, A. January 31, 2014. Sub-$50 Android smartphone hits South Africa as MTN launches Steppa. Retrieved from
http://www.zdnet.com/sub-50-android-smartphone-hits-south-africa-as-mtn-launches-steppa-7000025828/.
Oxford, A. September 19, 2013. Two-thirds of South Africans will be online by 2017 as mobile data booms, Retrieved
from http://www.zdnet.com/two-thirds-of-south-africans-will-be-online-by-2017-as-mobile-data-booms-7000020901/.
Smartphone Momentum Still Evident with Shipments Expected to Reach 1.2 Billion in 2014 and Growing 23.1% Over
2013. May 28, 2014. Retrieved from http://www.idc.com/getdoc.jsp?containerId=prUS24857114.

Device Ecosystem
Android has been evolving for the last several years and expanding its reach through various phones and tablets. At
Google I/O 2014, they announced that they are standardizing the Android landscape across phones, tablets, in addition to
wearable technology such as Glass and Wear, TV and even cars! All of these devices run the Android OS and give you
many avenues to create innovative new systems.

Android Wear
One of the latest additions to the unified platform is Android in watch form.
This exciting new platform not only provides notifications (similar to the status bar on your phone), but also provides new
modes of interaction. If you have an existing application with notifications, you already have a presence on Wear.
If you're interested in Wear, check out Android's website: http://developer.android.com/training/building-wearables.html

Google Glass
Google Glass is a notification engine, camera, video recorder, and application host on your face. Controversy aside, there
are plenty of interesting technical aspects to explore.
There are two basic flavors of Glass apps. First you can write applications with the mirror API, which delivers content to
your Glass using your own backend. You deliver HTML-based cards for display.
The other option is to write native Android applications using the Glass Development Kit (GDK). If you're interested in
developing Glass apps, check out the developer website: https://developers.google.com/glass/develop/gdk/

Android TV
Google's latest attempt at putting Android on your TV was announced at Google I/O this year. Instead of running a fork of
Android, as the ill-fated Google TV did, it now runs full, native Android. It also has casting abilities builtin (integrated
Chromecast).
If you're interested in developing TV apps, here's more info: http://developer.android.com/preview/tv/start/index.html

Android Auto
We know relatively little about the platform since it was recently announced, but it'll work as a second display and an input
device. Your apps will run on the integrated Android device in the dashboard (not on the car).

Design Considerations
Designing a mobile application is very different from designing for a PC. On a PC, you can assume fast processors, sizable
memory, lots of storage space, and a large display. Users are generally expecting to spend a lot of time in your application
to accomplish a larger goal, such as writing a book or doing their finances.
A mobile phone is a very different device! Users interact with it in very different ways than they do with a normal computer.
They are often accomplishing short tasks while on the go.

Hardware considerations
According to Meier, "compared to desktop or notebook computers, mobile devices have relatively:
Low processing power
Limited RAM
Limited permanent storage capacity
Small screens with low resolution
High costs associated with data transfer
Intermittent connectivity, slow data transfer rates, and high latency
Unreliable data connections
Limited battery life"

Battery usage
Mobile phone batteries are notorious for quickly losing a charge and people get very frustrated when they can't use their
phone for an entire day. Many people carry about battery boosters and chargers so that they will have access to their
phones after a day of heavy usage. You should write your applications to be a battery friendly as possible.
This is even more important in the further flung regions of the world, where Kochi shares that "recharging your phone every
night is not an option if you live in a rural village without electricity. At one of UNICEF's projects in rural Senegal, I
encountered a village entrepreneur who started a business where he would collect everyone's cell phones and for a small
fee, bike to an electrified village a few hours away, then bike back with phones at full charge."
Kochi further states that, "people in these countries spend a lot of money to keep their phones charged. Developing a
phone whose battery lasts for a week," and applications that don't needlessly waste battery power, "would unlock
smartphones to a large market segment."

Data usage
It's expensive to purchase data. We're fairly lucky in the United States to have ubiquitous access to networks on the go and
affordable plans. That's not always the case, even in other developed nations.
To be a better device citizen, limit the amount of data you download while on mobile networks and maximize the amount
you download and upload when users have a faster connection, such as Wi-Fi.

Unknown environments
You have no idea what device will be running your application, especially since the Android OS is ever expanding to new
devices and form factors. You must design responsive apps that scale to the multitude of devices on which your application
could run.

Attention span
Another thing to keep in mind is that your user's attention span is much shorter when using a portable device. Users are
usually engaged in a different activity when using your app, e.g. attending a party. Short bursts of activity like sharing a
picture on Instagram, sending a tweet about the festivities, or sending a text to meet up with their friends is the name of the
game.
You also can't assume that you have their full attention span for long. You want your designs to be beautiful and intuitive to
help them quickly accomplish their task.

Principle of least surprise


You don't want your users to be surprised by your application. You want to make sure that your designs are intuitive and
behave in ways that are easy to understand. A general rule of thumb is if you need a lengthy tutorial to introduce your user
to the interface, it's probably too complicated!
You also don't want users surprised by a background action or location-based action that they haven't explicitly signed up
for. A great example of what not to do is regularly annoying them with notifications about rating your application or sending
ads when they haven't requested them.

References
Kochi, E. May 27, 2012. Retrieved from http://techcrunch.com/2012/05/27/mobile-developing-world/.
Meier, Reto (2012-04-05). Professional Android 4 Application Development (Kindle Locations 1123-1128). John Wiley
and Sons. Kindle Edition.

Emerging Use Cases


In several cultures tablets and even phones are viewed as communal devices that are shared for the benefit of the
community. That is a different model than we typically assume in the United States!
Here are some of the most interesting emerging use cases in developing nations.

Mobile Payments
According to Kochi, "airtime has become another form of currency. Imagine you need to get a small amount of money to
your sister who lives in a village that's ten hours drive away. The easiest way for you to do that is to buy some airtime, but
instead of topping up your own prepaid mobile service you top up hers. For a small fee, she can now go and cash out this
airtime with an agent that sells airtime."

Activism
Ogunlesi also shares that phones are able to "able to transform ordinary citizens disenchanted by their governments, into
resistance fighters." The ability to share pictures and text in real time is a powerful way to fight brutal and/or corrupt
regimes. On the flip side, they can make citizens easier to track.

Disaster Management
Mobile phones can speed reconnection with loved ones in refugee camps by providing a SMS or other registry for
displaced persons (Ogunlesi). They could also be used to coordinate volunteer efforts on the ground.

Agriculture
According to Ogunlesi, "by serving as platforms for sharing weather information, market prices, and micro-insurance
schemes, mobile phones are allowing Africa's farmers to make better decisions, translating into higher-earning potentials.
Farmers are able to send a text message to find out crop prices in places thousands of kilometers away."

Health
According to Tsao, in Uganda, "less than 21% of births of children less than five years old are registered." A mobile platform
was developed so that "individuals can register births and deaths."
Also "malaria, a disease affecting nearly 3.5 billion people, has the opportunity to be the first disease beaten entirely by
mobile." There are several efforts including a mobile reminders for using bednets, enable donations, and increase access
to testing and treatment (Tsao).

Human Trafficking
"Traffickers, through the use of mobiles, are able to organize, advertise, and streamline their illicit activities while expanding
their criminal networks. As a consequence, more people are enslaved than at the height of the Atlantic trade, and partly
due to an additive ability to communicate." Mobile provides a variety of tools that could make this a much riskier business
by increasing communication capabilities and physical tracking through GPS (Tsao).

References
Ogunlesi, T. and Busari, S. September 14, 2012. Retrieved from http://www.cnn.com/2012/09/13/world/africa/mobile-

phones-change-africa/.
Kochi, E. May 27, 2012. Retrieved from http://techcrunch.com/2012/05/27/mobile-developing-world/.
Tsao, C. October, 8, 2013. Retrieved from http://www.huffingtonpost.com/clara-tsao/6-ways-mobile-techologyh_b_4054076.html.

Chapter 2: TDD with Robolectric


I completely agree with Martin Fowler:
To me, legacy code is simply code without tests. ... Code without tests is bad code. It doesn't matter how well written
it is; it doesn't matter how pretty or object-oriented or well-encapsulated it is. With tests, we can change the behavior
of our code quickly and verifiably. Without them, we really don't know if our code is getting better or worse.
Unit testing is a fundamental aspect of computer science that is often ignored. We never talked about it in college and I
didn't start hearing much about it until a few years into my coding career.
I am a fairly recent convert to unit testing. At first I didn't see the value. It felt like extra work. A few years ago, I spent three
months of intense pairing with another Android developer and it changed my whole outlook! Seeing how much we wrote
each day and how much confidence we ended up with in our design was refreshing. It was a departure from other groups I
had worked with that only valued quick code. This mentality encourages gun slinging, cowboy coders.

Android
Many languages and frameworks highly value testing, but it's an area that Android overlooked. There are some testing
capabilities in Android, but they rely on the emulator or an attached devices and are too slow to use as the primary means
of testing during the development phase. This type of testing is better suited for functional and/or integration-based testing
of features in your application.
When not using testing, the alternative is to build the application and see what happens, look at app to verify expected
behavior, and read logs. It's not terribly efficient!
Unit testing is a best practice, but has been particularly difficult in Android. One library that makes this process much
simpler is Robolectric.
Robolectric allows you to focus closely on the application you are building as you build out piece by piece. You write just
enough code to pass the tests. It allows you to do targeted and broad refactoring without worrying about breaking the rest
of the system. It helps us write better code and helps keep us on track.

Robolectric
Robolectric was created to run core Android components on the JVM and allow developers to verify aspects of their code
as they are developing instead of after the feature has been deployed to an emulator or device.
Running tests on an Android emulator or device is slow! Building, deploying, and launching the app often takes a
minute or more. That's no way to do TDD. There must be a better way.
Wouldn't it be nice to run your Android tests directly from inside your IDE? Perhaps you've tried, and been thwarted
by the dreaded java.lang.RuntimeException: Stub!?
Robolectric is a unit test framework that de-fangs the Android SDK jar so you can test-drive the development of your
Android app. Tests run inside the JVM on your workstation in seconds.

Lab Background
This lab will walk you through using IntelliJ to generate the project and maven to make integrate Robolectric.
After creating an Android project with the wizard, you move the source files into a mvn-like structure. Then you configure
module settings in IntelliJ. To install Robolectric, you will add a pom file (maven dependency file) into the project. Finally,
you will write your first test and run it inside the IDE.
Integration can be tricky, especially when creating a project from scratch. I'm a huge fan of living in IDE-land as much as
possible, so this approach minimizes command line work and manual project configuration.

github
A version of this Calculator project can be found here: CalculatorLab.
It has tags for all the major steps to help you as you work through the labs. If you wanted to follow along from the
beginning, start with the tag 2.2-step1 . Each tag matches up with the chapter's section numbers.

Prerequisites
You have installed IntelliJ (CE edition).
You have installed the Android SDK and configured IntelliJ to use it ( tutorial here).
You have maven installed.
You have installed maven-android-sdk-deployer and deployed at least one SDK, but preferably all, to your local
~/.m2/repository .

References
Adapted from: Latislaw, C. August 3, 2012. Integrating Robolectric with IntelliJ. Retrieved from
http://chariotsolutions.com/blog/post/integrating-robolectric-with-intellij/.

Robolectric Integration
Step 1: Create Android project
Use the IntelliJ Android wizard to create a Hello World project. First, choose the storage location and platform.

On the next screen:


Name your application Calculator
Create a "Hello, World! activity" and name it CalculatorActivity
Set the package name to com.mobiquity.calculator
Choose "USB device" as the "Target Device"

Step 2: Set up directories for maven


Use IntelliJ or the command line to move files into the following structure:

src/main/java/...
src/test/java/...

Note: IntelliJ might not like it when you add subdirectories to the folder marked as source. If you are having trouble setting
up the directory structure, open the screen shown in the next step and remove the old source folder before adding new
subfolders.

Step 3: Configure IntelliJ source and test folders


Update module settings in IntelliJ to recognize the source and test directories (below: blue folder is source and test folder is
green).

After you are done, your project should look something like this:

Step 4: Integrate Robolectric


Copy this sample pom.xml into live in the root of your project. Change the groupId to suit your project (e.g.
com.mobiquity.calculator ). If desired, also edit the artifactId , version , and name values.

Step 5: Maven
Check "Maven Projects" view in IntelliJ to ensure that it looks something like this:

If you see errors, you may just need to refresh and wait for it to finish indexing/importing your libraries. It may help to run
mvn install on the command line and restart IntelliJ.

If you are still having issues, your Android facet may be the problem. Open the Android facet for your project and change to
"Generate by IDE."

References
Adapted from: Latislaw, C. August 3, 2012. Integrating Robolectric with IntelliJ. Retrieved from
http://chariotsolutions.com/blog/post/integrating-robolectric-with-intellij/.

Lab: First Test


Let's write our first test!

Step 1: Create test file


I use the IDE to generate a test in the correct folder. Open CalculatorActivity.java and place your cursor on the name of
the class.
Use the Mac key combination Command + Shift + T to create the test for this class.

Step 2: Test runner


We need Robolectric's help to run our tests. Add this line above the test class name and import associated classes.

@RunWith (RobolectricTestRunner.class)

Step 3: Set up
Add a field for the activity under test so that we can access it in all of the tests in this class.

CalculatorActivity activity;

Then use setUp() to populate our field.

@Before
public void setUp() throws Exception
{
activity = Robolectric.buildActivity( CalculatorActivity.class )
.create()
.start()
.resume()
.get();
}

We use the Robolectric lifecycle management functions to build and start an activity. The last function call, get() , returns a
test instance that you can use to verify various aspects of the activity's view and behavior.
Note: The calls to create() , start() , and resume() reference the different phases of Android's activity lifecycle.
This will be covered in detail in Chapter 6: Managing the Lifecycle.

Step 4: Test
Write a test for the activity.

@Test
public void shouldNotBeNull() throws Exception
{
assertNotNull( activity );
}

Step 5: Create a run config for all tests


You could run each test individually as you work with new classes, however it should be a common task to run all the unit
tests (e.g. prior to commit). I create a run configuration for the whole project. Let's create a run configuration that will run all
the tests at once.
First, choose "Edit Configurations ..." from the "Run" drop down menu.

Then, hit the + button and choose JUnit.

Then select, "All in package" and give your configuration a descriptive name.

Step 6: Run
Use the run configuration created in the previous step to ensure our tests pass.

If you forgot step 2, you'll see this error message:

java.lang.RuntimeException: Stub!
at android.content.Context.<init>(Context.java:4)
at android.content.ContextWrapper.<init>(ContextWrapper.java:5)
at android.view.ContextThemeWrapper.<init>(ContextThemeWrapper.java:5)
at android.app.Activity.<init>(Activity.java:6)
...

In the future, you can right click on the test file name or a method name to run a test, use a keyboard shortcut, or run them
from the command line with mvn clean install .
If you are still seeing issues, rebuild your project a few times to convince IntelliJ to generate the R.java file (which links to
all your applications resources) and/or run mvn install from the command line.

Step 7: IntelliJ git integration


We can use IntelliJ's tools or the command line to commit our changes to a git repository. This step shows you details for

the IDE route.


First we want to tell IntelliJ that we will be working in a git repository. Use the drop down menu VCS -> Import into Version
Control -> Create Git Repository to complete this step.
TODO: Insert image
After we have integrated git, let's view our current change set. Use the drop down menu VCS -> Show Changes View to
see our current changeset.
TODO: Insert image
Before we commit, we need to make sure that we're happy the files listed in our change set. There are several files we
should ignore, including IntelliJ's project files located in the .idea/ folder, the .iml file for your project, and the gen/
directory (used behind the scenes during the build process). Let's use IntelliJ's tools to do this within the IDE.
TODO: Insert image
Note: The IntelliJ wizard adds a few files we won't need since we're not using the ant build tool. We can safely delete
these files inside the IDE by right clicking on the file and selecting delete. These files are ant.properties ,
build.xml , project.properties , local.properties and the bin/ directory.

Note: We also remove proguard-project.txt for the time being. If proguard is desired for your project, you can
configure it using this file.
Once we're happy with the change set, let's commit. You should always review the files and changes you're about to
commit after passing all project tests.
TODO: Insert image
Now let's talk about what to test!

References
Adapted and expanded: Latislaw, C. August 3, 2012. Integrating Robolectric with IntelliJ. Retrieved from
http://chariotsolutions.com/blog/post/integrating-robolectric-with-intellij/.

Testing Considerations
In this section, we'll cover some of the most common types of test cases and best practices to consider when determining
your testing strategy.

What To Test
You should focus your unit testing on business logic, basic view validation, and functionality. You can validate certain
requirements very well with unit testing (e.g. "when I click this bell image, it whistles" or "all activities have a logo on the
screen").
Here are some common examples:
Ensure the activity and view elements are not null.
Ensure expected fragment and view elements are visible on the screen.
Ensure that the proper resources are used for view elements.
Ensure items are hidden when expected.
Ensure toasts are shown.
Ensure that your intent starts the correct thing.

What Not To Test


I don't recommend investing much time in verifying less important styling details and XML attributes. Your user interface is
likely to change many times a week, but typically the basic view elements and their behavior remain the same. If you
updated a test each time a button had new padding, that would get very tedious indeed!

Example
The app logo is 250dp high with a proportional width, the file name is main_logo.png , it has a 20dp left margin and 12dp
right margin, has a content description of "Text" , and is centered vertically on every screen.
Returns start diminishing pretty quickly when you verify every possible XML attribute! Your time is best spent on items that
are relevant to business objectives. From this example, likely the most bang for your buck will come from testing that the
proper image is used and making sure that it appears on all expected screens.
Remember any of the attributes you don't test can be caught by designers, quality assurance, business, product, and/or the
engineers. A solid strategy is to sweep the app near deployment with a designer to make sure the app appears as expected
on a wide range of devices.

Additional Examples
Simple
Animation

References
Latislaw, C. August 7, 2012. Android Unit Testing With Robolectric. Retrieved from
http://chariotsolutions.com/blog/post/android-unit-testing-with-robolectric/.

Best Practices
Simplify Your Architecture
As with most object oriented realms, attempt to simplify the architecture as much as possible. Do this by creating abstract
or base objects or interfaces. This way you can test shared behavior in one place instead of several, which simplifies tests
and reduces code duplication.

Mock/Stub Functionality
Often we want to ensure that a certain action was performed but not actually run the code. To do this, you create a test
class which extends the class under test and override/mock out/track that a particular function was called.
For example, if you want a particular click to make an API call, there is no need to make the actual call (since this would be
an integration level test anyway). You can use this strategy to track that the function that invokes the call has been called,
but avoid making the actual call.
This is can also be helpful when an operation crashes the unit testing framework (e.g. specialty library that causes funky
side effects), doesn't play nice, or is otherwise unnecessary to invoke directly.

Utility Functions
I create several utility classes to improve the readability of my code. These live in my test structure under the package
support . We'll add these files in the next lab.

Centralize Test Constants


Android strongly encourages the use of abstracting string resources into one place over using hard-coded string constants.
I like to follow a similar pattern and use a test constants class when you have lots of test data. This can be really helpful
when creating a user with lots of fields to mock out a JSON response.

Don't Repeat Yourself (DRY)


If you find yourself writing something more than once, that's an excellent time to reassess. Luckily since you will have a
large base of unit tests at your disposal as well as powerful IDE tools, the refactoring will have minimal impact on the rest of
the system!

Robust Testing Strategy


Finally, you shouldn't rely solely on unit tests to ensure the proper behavior of your app. These tests, though quite useful,
only give you a small window into your app and it's behavior. At minimum, you should include integration level tests and
have some level of manual QA in the process to ensure your app is everything that you want it to be.

References
Latislaw, C. August 7, 2012. Android Unit Testing With Robolectric. Retrieved from
http://chariotsolutions.com/blog/post/android-unit-testing-with-robolectric/.

Lab: Utility Functions


Let's add utility functions to our support package. It'll help reduce the some of the boilerplate when we work through later
labs.
Technically with TDD you'd wait until the exact moment you need the code to write it. I prefer practicality over being
pedantic.

Create Assert.java
public class Assert
{
public static void assertViewIsVisible( View view )
{
assertNotNull( view );
assertThat( view.getVisibility(), equalTo( View.VISIBLE ) );
}
}

Create ResourceLocator.java
public class ResourceLocator
{
public static String getString( int stringId )
{
return Robolectric.application
.getString( stringId );
}
public static Drawable getDrawable( int drawableId )
{
return Robolectric.application
.getResources()
.getDrawable( drawableId );
}
}

Create FragmentUtil.java
With the version of Robolectric we're using, we need to make our own version of a fragment starter.
Robolectric has one for support fragments, but doesn't have one for "normal" platform fragments. This should be in
an upcoming release. We've copied their framework version here and modified to use normal fragments. You can
find the latest source for FragmentTestUtil on github.

public class FragmentUtil


{
public static void startFragment( Fragment fragment )
{
Activity activity = createActivity();
FragmentManager fragmentManager = activity.getFragmentManager();
fragmentManager.beginTransaction()
.add( fragment, null )
.commit();
}
private static Activity createActivity()
{
return Robolectric.buildActivity( Activity.class )

.create()
.start()
.resume()
.get();
}
}

Other Testing
There are many other forms of testing that you can incorporate into your development lifecycle. These other tools are
outside the scope of this book, but are listed here for easy reference and future exploration.

Android
Here are the Android sanctioned ways to test.

Instrumentation Testing
You use Junit style tests and create a test application that runs with your normal application. The test application exercises
the user interface.
It can be great for functional or integration testing, but since it relies on an emulator, it's just too slow for as-you-arebuilding-a-feature testing.
http://developer.android.com/tools/testing/testing_android.html

uiautomator
This testing framework runs on the device and uses accessibility features to conduct functional testing.
http://developer.android.com/tools/help/uiautomator/index.html

monkeyrunner
This framework allows you to script test in Python and runs your tests on an emulator.
http://developer.android.com/tools/help/monkeyrunner_concepts.html

Other Tools
There are many tools out there. Each application may lead to a different selection!
Calabash: http://calaba.sh/
Robotium: https://code.google.com/p/robotium/
Appium: http://appium.io/

Chapter 3: Architecture
Now that you know why Android is such a compelling system, let's look at how the system is constructed. A lot of pain and
suffering can be spared if we follow Android's conventions and loosely coupled model. Writing code this way makes it
easier to write and maintain. We should strive not only to make beautiful code, but also engaging personal, and fast
experiences for our users.
There are many layers of decoupling in the Android system. The applications are independent entities that can send
messages, but never know too much about each other.
The model is abstracted away from the display of the data and accessed by content providers and other mechanisms.
Views are abstracted from the business logic and into XML files that make it easy to change the appearance of the view
without changing the way that the view works.
Views are also decoupled from the resources that they use and the logic from choosing which view is right for the particular
device it is running on.
Assets and other content are abstracted from the view and business logic so that the content can change without requiring
an update in the code to support small copy changes.

Android
Android is an open source software and hardware system that sits on top of a Linux kernel. It also includes devices and the
set of applications that run on the OS.
You can browse the source Android Open Source Project (AOSP) at source.android.com.

Architecture Layers
Android's architecture has many layers.

If you'd like detailed information about the stack and Android's security features, you can read more here:
http://source.android.com/devices/tech/security/index.html
The top of the stack is where all the builtin applications, 3rd party applications, and your applications live. All apps here are
created equal and have the same access to the rest of the stack.

The second layer includes the application framework, which gives you the tools to write applications, such as the SDK,
activity managers, location managers, notification managers, and the view system.
The hardware access layer is where libraries are located for interacting with GPS, Wi-Fi, Bluetooth, NFC, and other
hardware features. The runtime is also at this layer.
Each application runs in it's own virtual machine (VM) instance, which means that applications can not directly invade each
other's process space. The system provides Linux-style permission controls while maintaining an open system through
Intents and other interprocess communication capabilities.
At it's lowest level, the Linux kernel handles drivers, power management, and other low level processes.

Compilation
The compilation phases include turning your Java files into .dex bytecode files, which is Android's version of Java
bytecode. An R.java file is created so that Java can refer to the XML components and other application resources.
The output of compilation is an .apk , which at it's heart is basically a .zip file.
Here's more detail here about the stages of compilation: http://developer.android.com/tools/building/index.html

Runtime
DEX bytecode is run on a virtual machine (much like Java runs on the JVM), called the DVM, or Dalvik Virtual Machine.
The DVM was written to be optimized for mobile devices.
Get all the low level details here: https://source.android.com/devices/tech/dalvik/index.html

In the future the DVM will be replaced with the new Android Run Time (ART).
Your application's resources are bound at runtime when Android determines which device it is running on and chooses the
best resources for that particular device.
Intents are also a run time binding. You issue a request and any app that can respond to the request will. The user chooses
which action to take based on a particular type of request or the system uses user's defaults.

Signing
Applications are signed with a key. This combined with the unique package name is what identifies an application on the
system.
By default, when you create development builds, you are using a default key to sign your application. You will use a
different key with a password when you prepare for release.
Note: Once you deploy your application with this release key you are forever stuck with the key and package name.
That's why it's so important to determine what you'd like to use for your package name and to always keep your
release key safe!

Note: It's possible to have both a debug and release signed version of the same application on your device since the
package name and signature are used together to identify an application.

Model View Controller


There are abstractions at every level to help you separate concerns, maintain code easier, and support the multitude of
devices and form factors in the wild. Android gives you tools to to decouple the presentation layer from the business logic.
Although some argue that Android is not a true MVC system, it's helpful to approach it in this way.

View
The view and resource system allows us to break out visual components. Android automatically handles most of the logic

about choosing which component to use for which form factor. You specify this in XML and put in special folders. This
enables scaling to different form factors as well as internationalization.

Controller
The Java layer is where you tie the visual components to the business logic of your application and where you would
access the model or data of your system. Services would also fall into this layer.

Model
Finally, the model layer is where you would store the data that powers the application. Content providers allow you to
abstract SQL queries away from your model's users and surface data throughout the application and system wide, if you
desire.

Building Blocks
An application is made up of a series of activity screens. These are strung together with intents to start up the next activity.
Activities are build of views and fragments. Fragments are built from views.
Activities are the major building blocks of your application and are roughly the screens that you see in an application. They
use fragments and views to construct the user interface that you see.
Activities are the major building blocks of your application and are the presentation layer, or screens you see in an
application. Activities are composed of views and fragments and several activities are combined to make an application.
From the activity you have access to all the views, resources, system state, and the model.
Services are used for long running applications, such as network operations.

Example:
This is an application with text views and buttons. When we click on the button it launches an activity.

We'll go over all of these in greater detail in later chapters.

Message Passing
Intents
Intents allow message passing and late run time binding between components. Basically you broadcast a desire, such as
opening a web browser or a specific Activity you created. Android handles the rest.

A good example is when sharing a picture you snapped with a social network. You have options, such as Twitter,
Instagram, etc. depending on what you have installed. If you are writing a camera application, you don't have to care about
how someone plans to share the picture, just that they are able to do it in the manner they wish.

Using intents frees you to focus on creating the content that is important to your application, not implementing or forcing
people to use a particular method. It makes your app a participant in the system instead of a self-contained app that must

handle everything by itself. You're part of the community!


You have several options with when invoking an intent:
Start one of your application's own components (e.g. by using startActivity() with an internal class). This keeps the
intent within the current process' boundaries.
Send an intent for an activity from another application that crosses process boundaries.
Broadcast a system-wide intent, such as opening a web browser or sharing a piece of content. This also crosses
process boundaries. The system presents the user with an option of how to react to the request.

Code Example
In this example, we are getting a reference to a button and setting a click listener that starts an internal activity.

findViewById( R.id.activity_button ).setOnClickListener(


new View.OnClickListener()
{
@Override
public void onClick( View v )
{
startActivity( ViewSystemActivity.createIntent( LooselyCoupledActivity.this ) );
}
};
)

Event Bus
Event buses are a great way to decouple our components without using a interface or listener pattern that can produce a lot
of boilerplate code. You can use an application-wide bus, such as Otto, to pass messages.

Threading Model
UI Thread
Android is an event driven system. The main UI thread loops indefinitely waiting for a new event or user input. When
something is received, it is processed.
If additional processing is required for a particular event that includes a long running operation, it should be done in another
thread. Examples of long running processes are network downloads, database lookups, or file I/O.
If you attempt to do long running processing on the main thread, it's likely you will either get an exception or activity not
responding dialog (ANR). This should be avoided at all costs since it's awful user experience!
Our first application doesn't do any of this sort of processing, so we will look at those topics in greater detail later.

Java Threads
You can do all the normal threading things you're used to with Java. You use Thread and Handler classes to post
information back to the main calling thread.

AsyncTask
These tasks are used to do background processing, but shouldn't be used for long running tasks. They have convenience
methods that allow you to interact with the UI thread before, during, and after your process is complete. These tasks are
tied to the Activity 's lifecycle.

Service
This is where you conduct long running processes that either handle networking, streaming, updating widgets, or a variety
of other tasks. Services live within your Application's process boundaries.

Background Fragments
You can also use a fragment without a view as a background worker. When you inflate the view, you set the view to null .
This is tied to the lifecycle of the Activity.

Chapter 4: Android Fundamentals


In this chapter, we'll go over the foundational building blocks of Android and extend our first application!
For this chapter, we'll be referring this example and starting our own project!

Calculator

Activities
Activities are written in Java and registered in the manifest. They live in the package structure that you define in the
manifest file. You can create subdirectories to better organize your files.

Code Example
public class LooselyCoupledActivity extends Activity
{
@Override
public void onCreate( Bundle savedInstanceState )
{
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_loosely_coupled );
}
}

Activity's Role
Wherever possible, you should strive make your activities as dumb as possible, essentially an empty shell for your
fragments. You'd also do work like configuring the action bar and menus here.
Ideally most of the business logic would be moved to Plain Old Java Objects (POJOs) for unit testing purposes, but in
practice some of that logic ends up in the subviews or fragments.
Often Activities are used as an intermediary between components (e.g. Fragments) because you don't want them talking
directly to each other. By using the listener pattern or a system bus, such as Otto, the components can post a message and
the Activity will read it and respond. This keeps the concerns separate and easier to maintain the individual components.

Activity Results
You can start an activity inside a hosting activity and get results from that activity.
You use startActivityForResult() to start the activity. In the activity that was started, you use setResult() to set the result
that will be returned. When back in the calling activity, you check the result code and respond appropriately.
A great example of this is invoking the system camera and then processing whether the picture-taking event was
successful: http://developer.android.com/guide/topics/media/camera.html

AndroidManifest.xml
The loosely coupled components (e.g. activities and services) are stitched together by the AndroidManifest.xml file at
runtime. This file describes each of your components and how they work together. You don't register fragments here
because they are transient and tied to the activity that hosts them.
In this file you specify which activity (or activities) that are launchable. You can specify how things are launched, how to
handle orientations, testing application information (when using instrumentation), and how to handle the SD card. Finally,
you specify metadata about the application like the name, version name, version code, icon, and theme.

Example
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.colabug.calc"
android:versionCode="1"
android:versionName="1.0">
<application
android:label="@string/app_name"
android:icon="@drawable/calc_icon">
<activity
android:name="CalculatorActivity">
</activity>
</application>
</manifest>

The package specifies the package structure for your application and is used to uniquely identify your application in the
market.
The application label refers to a string resource that will be shown on the launch grid of the device. Using a string
resource allows you to customize for internationalization. We'll cover resources more in depth later.
The versionName is a public-facing name for the version of the application. The versionCode is an integer value. You
should increase it for each release to the market and generally when developing the application and doing internal
releases. The version code combined with the signature and package name is what tells Android device users that there is
an update for their phone.
Inside the <application> tag, you specify the activities and services that you will use in the application.
If you create an activity and don't register it in the manifest, you will get a crash with a surprisingly helpful error
message.

Manifest Filtering
This file is also used as a filter by the Google Play store. You can specify application permissions, what hardware features
you require, and what OS versions you support.
If the user's device doesn't support one of your requirements, then it won't be shown in search results when they search on
the device. If they search on the web, they will find your app, but won't be able to install on devices that don't support your
application's requirements.
You can find more about filtering in the store here: http://developer.android.com/google/play/filters.html

Layouts
Layouts are where you define the view of your application using builtin Android views, view groups, and/or your own
custom views based on them. These XML files live in your res/ directory. Writing layouts this way allows us to decouple
the presentation layer from business logic.
Although you could write all your views in Java, that makes it a lot harder to leverage the full power of resource system.
Plus it often becomes a maintenance issue.

Example: activity_loosely_coupled.xml
There is always one parent at the root of the layout and the layout may contain many views.

<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
<!--Welcome string-->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/WELCOME_TEXT"
style="@style/Text"/>
...
<LinearLayout/>

XML views
There are many prebuilt items that you can use, including Button , TextView , ImageView , grids, and more!
You give each view an id so that you can wire up to logic in the Java class that points to this view. The system generates an
R.java file behind the scenes that maps your resources and views to a Java-accessible construct. This is generated at

compile time, but the decision of which view to show is determined at runtime.
Note: Sometimes the R.java files gets out of sync with your views and resources. This often happens if you change
a lot in a small amount of time. If you start seeing weird class cast exceptions, then this may be your culprit.
In this example, the view activity_button is defined in activity_loosely_coupled.xml with an id:

<!--Activity button-->
<Button
android:id="@+id/activity_button"
android:text="@string/ACTIVITY_BUTTON_TEXT"
style="@style/Button"/>

Referencing in the activity


In the activity, you use setContentView() to specify which layout to use and Android brings it to life. After that, you can
access its subviews with the id you gave it in the XML file.

findViewById( R.id.activity_button ).setOnClickListener( new View.OnClickListener()


{

@Override
public void onClick( View v )
{
startActivity( createViewSystemIntent() );
}
};
}

In this example layout we can make the activity button do something by referencing it in onCreate() . Here we attach a click
listener that will open another activity.
You can change all manner of information about the views. Good examples are setting the text or colors to display,
animating views, and/or attaching user actions.

Inflation
The XML gets turned into Java components at runtime when the Android system "inflates" the view.
As shown above, with an Activity the inflation occurs in the lifecycle method onCreate() with the setContentView()
function.
It's a little different in Fragment 's because the inflation occurs in the lifecycle method onCreateView() by using the
inflate() function.

When views are inflated, they are added to the view hierarchy. Any time that you add subviews or view groups, you are
deepening the hierarchy tree that represents your views. You can use the Hierarchy Viewer tool to optimize views that are
loading slowly.

Custom views
All of the view components are Java classes, which means they can be extended!
You can add custom behavior when a builtin components provide some, though not all of the behavior you'd like. You can
also create custom views that are collections of the basic view types.
For example, say you wanted to create a date and time clock. You could create a view that combines a TextView for the
date and and image or other control to show an analog version of the time).
These views are only limited by your imagination! We won't be covering them in depth in this class, but there's an excellent
presentation by Chiu-Ki Chan: Custom Components.

View Groups
A way to organize and simplify your XML layouts is to use view groups. You can use them to hold children views and make
reusable components. You can also extend them to add your own behavior.
Here are some of the most commonly used options.

FrameLayout
This is the simplest of the view groups. It's designed to hold one child view. This layout is often used as a holder for
dynamic fragments.

LinearLayout
As the name implies, with this name you lay view items out in a line, either vertically or horizontally.

RelativeLayout
With this view group, you can lay out elements in a relative fashion. For example, place the star to the right of the circle and
the heart below the circle.

GridLayout
With this view group, you can lay out similar elements in a grid fashion. This available in later OS versions and has been
back ported for older OS versions.

View Stubs

When your views start to get complicated, you can break it up using view stubs. This can be used to lazily inflate views at
runtime.
More information here: http://developer.android.com/reference/android/view/ViewStub.html

Fragments
An activity is the starting point for a screen, but if we put all the views and their logic together it quickly dissolves into a
huge mess! A much better way to construct your views is with fragments to further encapsulate the view logic into selfcontained pieces.
It breaks the logic of the activity up into self-contained pieces that handle user input. This is great for a lot of reasons. It lets
you reuse these components in other layouts to support different form factors without changing code, just constructing a
new layout with a different arrangement of fragments and views.
Activities hold fragments, which can't live outside a host. The activity reacts to notifications from the fragment that the view
should be altered. The fragment holds a reference to the hosting activity and can access it by calling getActivity() .

Master Detail Pattern

Consider the example application above. The tablet version has a list of articles on the left side of the screen and a detail
pane on the right. The phones uses two separate activities to show these views.
When a user selects a new article to view, the fragment on the right should update. You wouldn't want the article detail,
such as an article about Doctor Who, to be responsible for updating the view to show an article about cats.
It also doesn't make much sense for the list to know a lot of information about the detail it's going to show. Here you would
use the Activity to determine which detail view next. This becomes important when you also have a phone implementation
that would appear in totally different activities.
So, how do we do it? When the user taps an article in the list, an event is triggered and the Activity responds to this
received event. In the case of the tablet, it will simply update the right pane. In the case of the phone, it would start a new
activity.

The Great Schism


Fragments weren't always around. They introduced a few years ago with the first tablets and Honeycomb (Android 3.x).

Dashboard, July 2014: https://developer.android.com/about/dashboards/index.html


It makes it complicated to support the full range of OS versions, but it's becoming more and more compelling to sunset the
older versions as their percentage continues to drop. As of the writing of this book, the percentage of OSes in the wild that
don't include Fragment 's is only 14% (combined percentages of Froyo and Gingerbread).
However, if you do intend to support older versions, they have back ported it all the way back to 1.6 using the support
library.

Lab: Design Chunking


In this lab we will learn about the Android visual paradigms by exploring the designs of existing applications. This will help
us develop a process for breaking down a design into implementable pieces. This will come in handy when starting new
screens.
After we finish this lab, we'll be ready to start building our application.
Please refer to the class handout for parts 1, 2, & 3. A solution handout details how the designs could be broken
down.

Android Design
Let's get familiar with the Android design site:
http://developer.android.com/design/building-blocks/index.html
This excellent resource lists the items you can use as well as best practices for the platform. We won't be covering Android
design in detail, but this resource is a great starting place for understanding the design language of the platform.
Make sure to check out Material Design resources to see what is coming with the L release later this year! Check out
this video for more information on trainsitioning from Holo to Material.

Note: See the appendix for more design resources.

Discussion Questions
What do you find interesting about the design language?
How does it differ from other platforms? Can you think of other platform features that don't feel at home on Android?
Do you find the navigation paradigms intuitive?
What do you think of the evolution of Android's design through the ages?
What do you think of Material Design? Had you heard anything about it before the class?

Part 1: Class Design


We'll break down the design of the Google Music app as a class.

Part 2: Pair Design


Please pair up, analyze the view, and identify view components they may have used to construct this view.

Part 3: Class Project


Let's start our calculator!
Work with your partner to identify at least two different ways to you could break down this view into XML components. We'll
start implementing soon!
The next time you're breaking down a design, think about how you can segment it into views and fragments to best support
the user experience you are going for.

Handout: Design Chunking


Part 1: Google Music
We'll work through this exercise together as a class.

Part 2: Twitter
Please pair up, analyze the view, and identify view components they may have used to construct this view.

Part 3: Calculator
Work with your partner to identify at least two different ways to you could break down this view into XML components.

Extra Credit
Choose your favorite application and break down several of their screens into design chunks. It's a great way to learn from
others!

Solution: Design Chunking


Part 1: Google Music
They use ActionBar (transparent), with a title of the album and one icon (search).

The action bar overlays an ImageView for the artist. Below that is an image of the album we're viewing. To the right of the
album is album information displayed in TextView 's and several options available just to the right of the album cover (either
Button 's or ImageView 's). This is likely a RelativeLayout since things are laid out relative to other items on the screen.

Under the album info is the list of songs for this album in a ListView . Each list view item is fairly simple collection of
TextView 's and an ImageView for album options. There's an ImageView that shows on a row only if the song is currently

playing.
Note: When scrolling down in the list of songs, the album and artist information is pushed off the screen so that you
can focus on the most relevant information. This would be a custom implementation to add this behavior.
At the very bottom of the screen, there is a custom view that allows you to play/pause the current song or open the full song
view that has a host of other options.
Note: This view is persistent throughout the application even if you browse other albums.

Part 2: Twitter
There's a lot going on in this design!
Twitter also uses an action bar with icons, no title, and an overflow menu. They use a tab controller just below the action
bar for the different tweet streams, which has a indicator for the current tab.

Your tweet stream is displayed in a ListView . Each tweet is has several pieces of data, such as text views and images that
represent retweets, authors, time since posting, etc.
At the bottom of the screen, they have a custom view that combines two buttons for posting images and an EditText
(custom implementation) for entering a new tweet.
Clicking on most options takes you to another activity.

Part 3: Calculator
There are many valid ways to break down a design. Each choice has consequences or benefits when we build out the
application.

In our class implementation, we'll be using two Fragments laid out in a LinearLayout with android:orientation="vertical" .

The DisplayFragment will handle the display. We'll use an EditText to display the numbers entered into the calculator as
well as calculations.
The ButtonFragment will contain and control the calculator buttons. We'll use a RelativeLayout to position many Button 's
for operations and numbers.

Discussion Questions
What was your design? How does it differ?
How do you think that will impact implementation?

Lab: Construct The View


Testing Reminder
Ensure the activity and view elements are not null.
Ensure expected fragment and view elements are visible on the screen.
Ensure that the proper resources are used for view elements.
Ensure items are hidden when expected.
Ensure toasts are shown.
Ensure that your intent starts the correct thing.

Lab: Add DisplayFragment


Let's do this together as a class.

Create DisplayFragment.java
public class DisplayFragment extends Fragment
{
@Override
public View onCreateView( LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState )
{
View layout = inflater.inflate( R.layout.display,
container,
false );
return layout;
}
}

Create the view


The XML view doesn't exist, so we'll create a file called display.xml in the src/layout/ folder. We'll add the specifics of
the view later.

<?xml version="1.0" encoding="utf-8"?>


<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
</LinearLayout>

Create DisplayFragmentTest.java
@RunWith (RobolectricTestRunner.class)
public class DisplayFragmentTest
{
@Test
public void shouldNotBeNull() throws Exception
{
DisplayFragment fragment = new DisplayFragment();
startFragment( fragment);
assertNotNull( fragment );
}
}

At this point we should be able to run the test successfully.

Add to view
Let's add our fragment to main.xml (layout file specified in setContentView() of the CalculatorActivity ).

<fragment
android:id="@+id/display_fragment"

android:name="com.mobiquity.calculator.DisplayFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>

Test presence in the activity


@Test
public void shouldHaveDisplayFragment() throws Exception
{
assertNotNull( activity.getFragmentManager()
.findFragmentById( R.id.display_fragment ) );
}

Test & commit


Make sure to run the tests and then commit your work to your repository.

Lab: Add ButtonFragment


Your turn! Please complete this task with your partner.

Create ButtonFragment.java
public class ButtonFragment extends Fragment
{
@Override
public View onCreateView( LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState )
{
View layout = inflater.inflate( R.layout.buttons,
container,
false );
return layout;
}
}

Create the view


The XML view doesn't exist, so we'll create a file called buttons.xml in the src/layout/ folder. We'll add the specifics of
the view later.

<?xml version="1.0" encoding="utf-8"?>


<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
</LinearLayout>

Create ButtonFragmentTest.java
@RunWith (RobolectricTestRunner.class)
public class ButtonFragmentTest
{
@Test
public void shouldNotBeNull() throws Exception
{
ButtonFragment fragment = new ButtonFragment();
startFragment( fragment);
assertNotNull( fragment );
}
}

Add to view
Let's add our fragment to main.xml below the DisplayFragment .

<fragment
android:id="@+id/buttons_fragment"
android:name="com.mobiquity.calculator.ButtonFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>

Test presence in the activity


@Test
public void shouldHaveButtonsFragment() throws Exception
{
assertNotNull( activity.getFragmentManager()
.findFragmentById( R.id.buttons_fragment ) );
}

Test & commit


Make sure to run the tests and then commit your work to your repository.

Lab: Display View


Add the view
Replace the LinearLayout from previous steps with this EditText in display.xml .
We can do this since each view expects only one view at the root, but may have more. Since our view is so simple, there is
no need to have an enclosing view group.

<EditText
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/display"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="20dp"
android:paddingBottom="20dp"
android:gravity="center"
android:textSize="40sp"
android:textStyle="bold"
android:textColor="@color/nearly_black"
android:editable="false"
android:maxLength="10"
android:inputType="none"
android:focusable="false"
android:focusableInTouchMode="false"
android:background="@android:color/white"/>

Here I've added many XML attributes! The attributes are mostly self explanatory, but I'd be happy to answer any questions
on particular attributes.
We'll learn more about abstracting some of the hard coded values out later into dimensions and styles.

Add colors.xml
For the background color I'm using a built in Android resource:

android:background="@android:color/white"

For the text color I defined a new color in res/values/colors.xml :

<resources>
<color name="nearly_black">#ff313131</color>
</resources>

Add test to DisplayFragmentTest.java


We going to refactor a bit here to make it easier to test new items. First, make a field, fragment , for the fragment under
test. Then, move the fragment initialization and fragment starting to the setUp() function.

public class DisplayFragmentTest


{
private DisplayFragment fragment;
@Before
public void setUp() throws Exception
{

fragment = new DisplayFragment();


startFragment( fragment );
}
@Test
public void shouldNotBeNull() throws Exception
{
assertNotNull( fragment );
}
}

Now we're ready to add the new test:

@Test
public void shouldHaveDefaultDisplay() throws Exception
{
EditText display = (EditText) fragment.getView().findViewById( R.id.display );
assertViewIsVisible( display );
assertThat( display.getText().toString(),
equalTo( "" ) );
}

Lab: Add Buttons


In this lab we'll add the buttons to the view complete with tests.
Note: They won't be pretty and they won't do anything!

Testing
As I build each key, I write a test. Then I add the next key. I typically don't start laying out the views or making them pretty
until they are all present in the view and the tests are passing. I commit after the views are present. Then I do a styling
commit afterward (we'll do that as a separate step).

Add a test
Last we saw this file, we had all the initialization code in the the test that we wrote. Let's make a field for the fragment and
move the initialization to the setUp() function:

private ButtonFragment buttonFragment;


@Before
public void setUp() throws Exception
{
buttonFragment = new ButtonFragment();
startFragment( buttonFragment );
}

Now we can add a new test.


We use getView() to get a reference to the view and then find the specific id.

@Test
public void shouldHaveOneKey() throws Exception
{
assertViewIsVisible( buttonFragment.getView()
.findViewById( R.id.key1 ) );
}

Add a button
Now we add the button to the view.

<!--1-->
<Button
android:id="@+id/key1"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_margin="5dp"
android:text="@string/key1"/>

Add a string
It's best practice to move your strings to the strings.xml file instead of leaving them hard coded in the view. It also makes
it easier to test that the correct string is configured for a view.

<string name="key1">1</string>

The lint tool will recommend this for you by showing yellow bars and a light bulb in the view.

Verify properties
Let's extend our test to ensure that the correct string is configured for the view. We'll use our ResourceLocator class to get
the resource string and compare it to TextView 's getText() return to ensure they are equal.
Our final test looks like this:

@Test
public void shouldHaveOneKey() throws Exception
{
TextView key1 = (TextView) buttonFragment.getView().findViewById( R.id.key1 );
assertViewIsVisible( key1 );
assertThat( key1.getText().toString(),
equalTo( ResourceLocator.getString( R.string.key1 ) ) );
}

Add all the buttons & commit


Add each number and operator key in turn and make sure the tests pass along the way. After you're done with the buttons,
commit.

Make it pretty
Let's replace our parent LinearLayout with a RelativeLayout so that we can define the position of the buttons relative to
the other buttons.
Please refer to the screenshot of the example project to determine where each button should be positioned.

<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
<!--1-->
<Button
android:id="@+id/key1"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_margin="5dp"
android:text="@string/key1"/>
<!--2-->
<Button
android:id="@+id/key2"
android:layout_toRightOf="@id/key1"
android:layout_alignBaseline="@id/key1"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_margin="5dp"
android:text="@string/key2"/>
<!--3-->
<Button
android:id="@+id/key3"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_margin="5dp"
android:layout_toRightOf="@id/key2"
android:layout_alignBaseline="@id/key2"
android:text="@string/key3"/>
<!--4-->
<Button

android:id="@+id/key4"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_margin="5dp"
android:layout_below="@id/key1"
android:text="@string/key4"/>
...
</RelativeLayout>

Note: There are many ways this view could be laid out. RelativeLayout isn't the most intuitive choice, but it is quite
useful and mastery of it early in your Android career will lead to great things.

Application
According to Meier at Kindle locations 2459-2461, you define your own application implementation when you need to:
Respond to application level events broadcast by the Android run time such as low memory conditions.
Transfer objects between application components.
Manage and maintain resources used by several application components.

Declaration
You declare your application in the manifest and the application class will be automatically instantiated when the application
is run.
It's best practice to declare your application as a singleton.

Lab: Add Application


Add to the manifest
Let's add the following attribute to our <application/> tag of our AndroidManifest.xml .

<application
android:label="@string/app_name"
android:icon="@drawable/calc_icon"
android:name=".CalculatorApplication">

Create class
Create a file called CalculatorApplication.java in the package structure. You can use the IDE to create it for you or do it
manually.
It's best practice to set it up as a singleton.

public class CalculatorApplication extends Application


{
private static CalculatorApplication instance = new CalculatorApplication();
public static CalculatorApplication getInstance()
{
return instance;
}
}

Write Test
Create a file called CalculatorApplicationTest.java in your test package structure. You can use the IDE to create it for you
or do it manually.
Let's add the basic non-null test:

public class CalculatorApplicationTest


{
@Test
public void shouldNotBeNull() throws Exception
{
assertNotNull( CalculatorApplication.getInstance() );
}
}

That's it! Now we can add more items to this class as we need them.
Let's commit our changes.

Lab: Event Bus


Event buses are a great way to decouple our components without using a interface or listener pattern that can produce a lot
of boilerplate code.
Otto is a system-wide notification system. A component (e.g. an Activity or Fragment ) posts an event, with an optional
message, to Otto. Other components that have registered for events will receive the event and react as appropriate.
Let's add an Otto Bus!

Integrate Otto
If not already present, add the maven dependency to your pom.xml file so that we can reference Otto throughout our
project.

<!--Event Bus-->
<dependency>
<groupId>com.squareup</groupId>
<artifactId>otto</artifactId>
<version>1.3.4</version>
</dependency>

Application bus
Now add these lines to our CalculatorApplication.java class.

private Bus bus;


public Bus getBus()
{
return bus;
}
public static void postToBus( BaseEvent event)
{
// Note: Auto Generating BaseEvent next
getInstance().getBus().post( event );
}
@Override
public void onCreate()
{
super.onCreate();
instance.bus = new Bus();
}

The function postToBus() gives us a convenient way post to the bus from any activity or fragment in our application. If we
build all of our events to extend the BaseEvent then we can use this for all events in the application.

Create BaseEvent
Create a file called BaseEvent.java . I suggest creating a package called events to hold events and create further
packages as needed to keep your code organized.
The event can be quite simple, or you can include data with your events. In this case, we will make it as basic as possible:

public class BaseEvent { }

Add a test & commit


Let's make sure that the Bus exists for our application. First we'll need to migrate our application to a field and initialize in
setUp() . Then we can add this test:

@Test
public void shouldHaveBus() throws Exception
{
assertNotNull( application.getBus() );
}

Once all the tests pass, commit to your repository.

Chapter 5: Resource System


Meier puts it well, "using layout resources decouples your presentation layer from the application logic, providing the
flexibility to change the presentation without changing code. This makes it possible to specify different layouts optimized for
different hardware configurations, even changing them at run time based on hardware changes (such as screen orientation
changes)."
I've seen a too many duplicated layouts, hard coded values, and hard coded Java views cluttering Android applications! All
of these practices lead to difficult to maintain apps and makes it harder to scale to newer devices and form factors.
However, if you leverage Android system from the start and let it do the heaving lifting for you, you can avoid a lot of pain
down the road.
Although I find XML a pain to read and write, I've grown to love the resource system. It is one of the most powerful tools you
have when constructing your application, but is often misunderstood and definitely underrated and underutilized.

res/
You place your layouts, drawables, and values (e.g. strings, colors, dimensions) in this folder.
The basic folder structure looks like this:

res/
drawable/
values/
layout/

One annoying thing about these folders is that you can't create subfolders. This is especially annoying in the layout folder
since you end up with lots of views in your system. You can however, make up your own file names and group resources
that belong together.
There's lots of great information on Android's site about how to suport mutiple form factors:
http://developer.android.com/guide/practices/screens_support.html

Resources
Meier, Reto (2012). Professional Android 4 Application Development (Loc.2816-2818). John Wiley and Sons. Kindle
Edition.

Design Principles
Think like a web programmer
In Android, you create styles (which is analogous to CSS), externalize your resources, and use what Android calls resource
qualifiers to adapt your design to different form factors.
If you have a web programming background, this will feel familiar. If not, the idea is that your view automatically scales to
suit the amount of space it has and you define how that view should adapt to new sizes.
Don't base you designs on specific devices or device categories, rather think about the natural separation or breaking lines
for your views. There is no "phone" or "tablet", they are just devices in a continuum.
Responsive design, as opposed to pixel-perfect designs, from the start will make it a lot easier to scale your views.

Let Android do the heavy lifting


Android dynamically selects resources at runtime that are best suited to the device running the application. You can set up
alternatives for things like orientations, hardware, languages, locations, view sizes, and more. It frees you from the burden
of figuring out in code what resource you should be showing if you use Android's system to do it for you.

Externalize Resources
Externalizing resources, such as images, strings, dimensions, styles, themes, and layout makes it much easier to maintain
and scale your views.
This is the heart of the Android - there are no guarantees of what your app will run on, so you need to create the most
flexible app and views possible to avoid headaches from hardcoded values.
The Activity class provides helper methods to get these resources such as getString(R.string.name) and
getDrawable(R.drawable.name) . There's also a method getResources() . Some of these are available in the Fragment class

and you can always ask for the activity's resources by calling getActivity().getResources() .

Scalable Layouts
Use relative positioning when laying out your views so that they adapt well when running on different screen sizes.
RelativeLayout and LinearLayout are great choices.

Use wrap_content and match_parent whenever possible when defining the layout_height and layout_width of your
views. wrap_content tells the system to measure the view at inflation and render the widget with just enough space to
contain it. On the other hand, match_parent says take up all the available width and height when rendering this view.

Styles & Themes


Styles and themes are specified in res/styles.xml . Themes are used for the overall appearance of the application, while
styles are applied to specific views.
In most cases, you won't need more than one style file. If you use abstracted dimensions and image assets in your styles
(as opposed to hard-coded values) combined with the qualifier system (all of which will be covered in depth in this chapter),
it makes your views scalable.
You can inherit from other styles and themes. You can override attributes and add new ones in derived styles or when
specifying view attributes in the layout file.

Styles
Styles allow you to abstract out view attributes into a centralized location to enable reuse.

Defining styles
In this example, I've defined a style called SquareButton that configures a height and width.

<style name="SquareButton">
<item name="android:layout_width">50dp</item>
<item name="android:layout_height">50dp</item>
</style>

Note: The syntax is a bit different from how you specify view attributes in your layouts, but they both use the same
XML attributes.

Using styles
After you define a style, you can reference it in the XML layout by using the style attribute:

<!--Square button-->
<Button
android:id="@+id/square_button"
android:text="@string/SQUARE_BUTTON_TEXT"
style="@style/SquareButton"/>

Note: style doesn't use the android namespace.

Themes
Themes provide a convenient way to apply style to an entire application or just an Activity.
This is useful because you can rapidly reskin your application by changing just a few lines of code.
To use a theme in your application, you specify it in the AndroidManifest.xml . You can either use Android's builtin themes
(example below) or create your own.

<application
android:label="@string/APP_NAME"
android:icon="@drawable/icon"
android:theme="android:Theme.Holo.Light.DarkActionBar"/>

If you want to customize a theme, you can extend an existing Android theme and adding attributes or override attributes as
desired.
AndroidManifest.xml

<application
android:label="@string/APP_NAME"
android:icon="@drawable/icon"
android:theme="@style/ApplicationTheme">

styles.xml

A theme is just a style. What makes it different is where you apply it!

<style name="ApplicationTheme" parent="android:Theme.Holo.Light.DarkActionBar">


...
</style>

Dimensions & Colors


My approach to dimensions and styles has evolved over time as I get exposed to new teams and new designers. I'll show
you what it took me a while to discover for myself in hopes of saving you some headaches down the road.
When I started with Android, the team and I gleefully threw hard-coded values all over the place, often duplicating values in
the same file! Not only did this litter the code, but it made debugging view issues more difficult.
Throughout this chapter I'll show you a scalable way to manage these resources.

Dimensions
It's straightforward to create a dimension. You'll need a dimens.xml file in res/values/ :

<resources>
<dimen name="my_dimen">25dp</dimen>
</resources>

You can reference them in styles:

<style name="YourStyle">
<item name="android:layout_width">@dimen/my_dimen</item>
</style>

Or inline in your XML:

<View
android:layout_width="@dimen/my_dimen"
android:layout_height="@dimen/my_dimen"/>

Or even in Java:

float dimen = getResources().getDimension( R.dimen.my_dimen );

Benefit
It might not be immediately apparent, but using dimensions with resource qualifiers (covered in depth later) allow you to
create responsive components. You'll see this in action in the "Flexible Dimensions" lab.

Colors
Abstracting colors gives you a convenient place to store and name your colors instead of using hard coded hex values all
over the place. Having names associated with the colors makes it easier to maintain view changes.
Plus you have an added bonus of previews of your color swatches and a color picker (including dropper!) when you are
open colors.xml in IntelliJ.

You can abstract many types of values. Check out this article for more information:
http://developer.android.com/guide/topics/resources/available-resources.html

Lab: View Styles


Let's make our calculator look nice! By the end of this lab we will create and apply styles to all of our buttons. We'll also
create a style for the display.

Color Scheme
Number button: #876D13 (Brown)
Operator button: #668113 (Green)
Equals button: #268474 (Blue)
Clear button: #B0281A (Red)

Create styles
First, create a file called styles.xml in res/values/ . This is where all of our styles and themes live in the application.

Base button
If you analyze the design, you'll notice that the buttons are basically variations on a theme. The only variants in the style are
different colors and some buttons are wider than others. Since these buttons are so similar, it makes sense to create a
basic style that each button type will inherit.
Let's add this base button style to styles.xml .

<style name="BaseButton">
<item name="android:layout_width">@dimen/button_dimensions</item>
<item name="android:layout_height">@dimen/button_dimensions</item>
<item name="android:layout_margin">@dimen/button_margin</item>
<item name="android:textSize">@dimen/key_text_size</item>
<item name="android:textColor">@android:color/white</item>
</style>

Here we've specified the height and widths of the view, the margin between the buttons, the color of the text, and the size of
the font. All but the last use abstracted dimen 's. We'll add these in the next section. For the final item (text color), we use
an Android supplied color instead of creating our own.

Create dimensions
Now it's time to start using dimensions!

Start by creating the dimens.xml file in res/values/ . Then add the base line values for the view. We'll add different
versions of this file in a later lab to scale to different screen sizes.

<resources>
<dimen name="button_margin">5dp</dimen>
<dimen name="button_dimensions">60dp</dimen>
<dimen name="key_text_size">30sp</dimen>
</resources>

Number style
Now that we have BaseButton and all the dimensions needed to make it a reality, let's use it to create our Number style.
You can inherit attributes from parent styles and add your own configurations for the newly derived style.

<!--Number-->
<style name="Number" parent="BaseButton">
<item name="android:background">@color/brown</item>
</style>

For now we'll set the background to a flat color. In a later lab we'll extend this style to provide visual feedback upon user
interaction.
Note: You can also inherit from multiple styles: http://developer.android.com/guide/topics/ui/themes.html#Inheritance

Create colors
Let's add colors to colors.xml for the new buttons. The Number color brown is shown below:

<color name="brown">#876D13</color>

Remove extra attributes


Another benefit of creating styles is that it will clean up our XML files. Remove any attribute that is covered by the style.
Here's the updated 1 key:

<!--1-->
<Button
android:id="@+id/key1"
android:text="@string/key1"
style="@style/Number"/>

Much cleaner! I move as much as possible to styles to keep my XML files lean. I generally leave attributes the source XML
file that relate to positioning in the view (e.g. RelativeLayout positioning), text for a button or text view, and the id.

Operators, Equals, and Zero


Using the information above, create and use styles for each of these key types. When you finish, the view should look like
the screenshot.

Display

Finally, clean up the display view in display.xml using a style.

Qualifiers
To set up alternative layouts and resources to be resolved at runtime, you use resource qualifiers.
Qualifiers cover things like screen size (width and height), languages and regions, aspect ration, orientation, and OS
version among others.
Check out the complete listing of qualifier options as well as detailed documentation on how resources are selected:
http://developer.android.com/guide/topics/resources/providing-resources.html

Folder structure
In this example res/ folder, we have a number of directories. Qualified folders can be recognized by the dash in their
name and tells Android to use specific resources for specific instances.

res/
drawable/
values-sw600dp/
values-fr/
layout/
layout-land/

-fr stands for French, -sw600dp means smallest width of the device is 600dp and higher, and -land is where the

landscape layouts live. You could combine several qualifiers into one folder by using a dash between each qualifier.

Resolution
There's a bit of Android magic that selects the best version of your view or resource for the current device. If you set up the
parallel folder structure to support different configurations, Android will handle the rest. Android chooses the best resources
at runtime based on the device that is hosting the application.
Android tries to match with the most specific resource qualifiers first and then falls back to more generic options. If none of
the resource qualifiers in your application match the host device, the basic values specified in layout/ , values/ , and
drawable/ will be used.

Make sure to have a sane default! If you define something in a specific qualified folder, such as an id, and then run the app
on a device with different specifications, it will crash because it won't be able to find the default value at runtime.
You might not catch this during development since you are likely using the same device. It's good practice to vary
your test devices and testing situations to explore unhappy paths.

Naming
In the case of layouts, if you want to override the view for a specific configuration, you will need to create another version of
the view in a qualified folder, but you use the same name for both files. That's how the resource qualification system works!
In the case of strings, dimens, drawables, and other resources, make sure to use the same name in the default and
qualified paths to override the value for your new configuration.

Example: Internationalization
In values/strings.xml I have strings for a welcome screen.

<resources>
<string name="WELCOME_TEXT">Hello Dutch Mobile Conference!</string>
<string name="ABOUT_TEXT">Programmed by Corey Leigh Latislaw</string>
</resources>

In values-nl/strings.xml I defined the same name, but put the file in the qualified structure and changed the text.

<resources>
<string name="WELCOME_TEXT">Hallo Dutch Mobile Conference!</string>
<string name="ABOUT_TEXT">Geprogrammeerde door Corey Leigh Latislaw</string>
</resources>

Lab: Flexible Dimensions


In this lab, we'll use the qualifier system and dimensions to scale our view for different form factors.
If you don't have access to a Nexus 5, please create an instance using Genymotion.

Remove ActionBar
The ActionBar in this case doesn't help our application since we'll only be showing one screen and don't have any
configuration or navigation options. It's just taking up valuable screen real estate!
On newer OSes you get it by default unless you explicitly exclude it in the manifest file:

<application
android:label="@string/app_name"
android:icon="@drawable/ic_launcher"
android:name=".CalculatorApplication"
android:theme="@android:style/Theme.NoTitleBar">

Alternate dimens.xml
Let's create a folder called values-w350dp and a dimens.xml in that folder. Here is where you'd put your values you'd like to
use on screens with at least 350dp in screen width.

<resources>
<!--Keys-->
<dimen name="button_dimensions">78dp</dimen>
<dimen name="button_margin">4dp</dimen>
<dimen name="key_text_size">50sp</dimen>
<!--Zero-->
<dimen name="zero_key_width">164dp</dimen>
<!--Equals-->
<dimen name="equals_button_width">250dp</dimen>
<!--Display-->
<dimen name="display_margin">8dp</dimen>
<dimen name="display_text_size">40sp</dimen>
</resources>

You don't have to copy all the dimensions over from values/dimens.xml - just the ones that you are interested in
overwriting.

Adjust display & commit


I adjusted my display margins after adjusting all my buttons to make the edges line up better.

Lab: Internationalization
Let's add Japanese numbers!
Create a folder values-ja and a strings file under this directory.
Copy the characters from here into your strings.xml folder for keys 0-9: http://en.wikipedia.org/wiki/Japanese_numerals

Add tests
Robolectric allows you configure the qualifiers for a specific test:

@Test
@Config (qualifiers = "ja")
public void shouldHaveJa0Key()
{
verifyKey( R.id.key0, R.string.key0, "");
}

I have a helper function to reduce the duplicated code for each key. You could refactor this even further into an array that
you loop through to verify each button.

Button key = (Button) buttonFragment.getView()


.findViewById( id );
assertViewIsVisible( key );
String resourceString = getString( stringId );
assertThat( key.getText().toString(),
equalTo( resourceString ) );
assertThat( expectedString,
equalTo( resourceString ) );

Build and change your device's language to Japanese to visually verify the internationalization worked.

Drawables
Drawables are the images in your application. These images can be in .png , .jpg , .gif , or specified in XML.
You save the files in drawable or a qualified version of the drawable folder and then reference in XML without the
extension.

<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
src="@drawable/myimage"/>

ColorDrawable, ShapeDrawable, GradientDawable


Instead of including an image with different densities, you could specify resources in XML and even Java.
For example, to draw a red rectangle, you could create it using XML.

<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<solid android:color="@color/Red" />
</shape>

You'd save the file in the drawable/ folder and give it a descriptive name like rectangle.xml . To refer to it in code, you use
the same method of referencing:

<View
android:layout_width="80dp"
android:layout_height="20dp"
android:background="@drawable/rectangle"/>

9-patch
This is a special file that scales to fill a view. You are able to specify how certain regions stretch and what regions should
stay the same.

You can find more information about using and creating these files here:
http://developer.android.com/tools/help/draw9patch.html

State List Drawables


You can also specify how views appear in different states via XML. A common usage is setting button interaction states.
You can define what it looks like normally, what it looks like when you press the button, what it looks like when focused (e.g.
through a keyboard or mouse interaction). We'll be doing this next in the lab!

Lab: Button State


Start by creating the drawable/ folder under res/ .

Selector
Create number_key.xml in res/drawable/ .

<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<!--Pressed-->
<item
android:state_pressed="true"
android:drawable="@color/selected_brown"/>
<!--Focused-->
<item
android:state_focused="true"
android:drawable="@color/focused_yellow"/>
<!--Normal-->
<item
android:drawable="@color/brown"/>
</selector>

Each item here corresponds to a different

Colors
You're free to choose your own colors and customize the design! I've added my colors for the different states to
res/colors.xml :

<color name="focused_yellow">#ffafb315</color>
<color name="selected_brown">#ff604613</color>

Apply in style
To make this all work, you need to associate it with the number keys. Edit the Number style to include this new drawable as
our background image.

<!--Number-->
<style name="Number" parent="BaseButton">
<item name="android:background">@drawable/number_key</item>
</style>

Now our buttons respond to touches!

Do this for each type of button and commit.

Lab: App Icon


Let's create an icon for our application!
Open Android Asset Studio and choose "Launcher icons".
Create an image of your choice and download the zip file. Opening the file you will see that there's several images inside
qualified folders. Move each of these images into the correct folders and add qualified folders that don't currently exit.
Override the existing icons when prompted.
Note: The tool doesn't provide a resource for drawable-ldpi .
We already have this file name specified in the manifest, so we won't need to update the file. In general, If you want to add
an icon, add it to the <application/> tag:

<application
android:label="@string/app_name"
android:icon="@drawable/ic_launcher">

Commit!

Chapter 6: Managing the Lifecycle


An application's lifecycle can be interrupted by many events, such as a user answering a phone call. It is imperative to
understand what happens when a user navigates away from your phone and then comes back since this will likely happen
often.
It's rare that a user will spend significant time in your application and progress through the screens exactly the way you
envision. A user is typically quickly consuming or sharing content and then moving on to the next thing. It's likely that the
user will exit and come back to your application many times a day. Depending on how they left your application and how
you manage the lifecycle, it could lead to some surprising results when they launch your application the next time!
We often overlook this fact when we are writing applications because we stare at it for a long time and work through the
application in a particular way (as it was designed). We end up only thinking about the happy path and miss many bugs that
arise from improper lifecycle management. Only by interacting with your application as a normal user would will you start to
see these quirks.
An application has a lifecycle. It's activities have a lifecycle. The activity may host one or more fragments that also have
their own lifecycles.
We'll go the lifecycles of these components in further detail in this chapter and end with a lab to solidify these concepts.

Application Lifecycle
onCreate()
Called when the application is starting, before any activity, service, or receiver objects (excluding content providers) have
been created. Make it fast, this affects startup performance.

onLowMemory()
When the overall system is running low on memory, you use this to trim memory usage. Release any caches or other
unnecessary resources you may be holding on to. The system will perform a garbage collection for you after returning from
this method.

onTrimMemory()
Called when the operating system has determined that it is a good time for a process to clear up unneeded memory. This
can happen when the application goes in the background and there is not enough memory to keep as many background
processes running as desired.

onConfigurationChanged()
Called by the system when the device configuration changes while your component is running.
At the time that this function has been called, your Resources object will have been updated to return resource values
matching the new configuration.

Activity Lifecycle
There are many states, but in practice you use onCreate() , onResume() , onPause() , and onDestroy() most often. The
activity goes through the creation flow when starting up and then follows a similar (but reverse) tear down flow when
moving to the background.

Active States
Created
When onCreate() is called, the activity is being created, but not yet visible to the user. You can get references to view
elements and configure long running processes.

Started
When onStart() is called, the activity is being created and may be visible to the user, but the user won't be able to interact.

Resumed
When onResume() is called, the activity is visible to the user and ready for user input.

Inactive
When onPause() is called, the activity is still partially visible. The user may have been shown a dialog or other item that
briefly takes the focus away from the active Activity. It's possible that they may resume the activity shortly, but you should
start preparing for the tear down.

Stopped
When onStop() is called, the activity is hidden and may be cleaned up if resources are needed for the new (and currently
displayed) activity that a user is interacting with.

Destroyed

onDestroy() is called right before your activity is destroyed.

This can happen either because the activity is finishing (someone called finish() on it, or because the system is
temporarily destroying this instance of the activity to save space. You can distinguish between these two scenarios with the
isFinishing() method.

Fragment
A Fragment 's lifecycle is tied to its hosting activity, but has independent methods as well.

Many of these lifecycle methods are similar to the Activity 's methods and are intertwined with the Activity 's state.
If you'd like more in depth information about the fragment lifceycle, check out Android's documentation: Fragment Lifecycle
and Coordinating with the activity.

onCreateView()
This is where you configure view components.

onActivityCreated()
After this phase, you have access to the Activity .

Lab: Visualizing the Lifecycle


Let's add logging to the lifecycle methods to see what's happening behind the scenes in CalculatorActivity ,
CalculatorApplication , ButtonFragment , and DisplayFragment .

Tagging
So that we can easily identify our log messages, add a constant field to each class:

private static final String TAG = "Lifecycle " + [ClassName].class.getSimpleName();

Make sure to replace [ClassName] with the name of the class (e.g. CalculatorApplication ).

Instrumenting
Use O to override the lifecycle functions.
Add a log call in each method. For example, your onCreate() should look like this:

@Override
public void onCreate( Bundle savedInstanceState )
{
super.onCreate( savedInstanceState );
Log.d(TAG, "onCreate()");
...
}

Run
You can filter the IntelliJ logs to show only a specific tag (the first string provided to Log.d() ):

Backstack
You can navigate forwards and backwards in an application.
The backstack keeps track of all new activities and fragments that were either implicitly or explictly added.
When you use startActivity() with an intent, it is automatically added to the backstack for you. With fragments, you can
explicitly add the fragment to the backstack when committing a FragmentTransaction .

Back button
You can intercept back clicks in an Activity , though be careful because you shouldn't violate a user's expectations.

@Override
public void onBackPressed()
{
...
}

FragmentManager
When Fragment 's are added to the view in an XML file, they are static and always visible to the user. You can't manage the
state directly, it is tied to the state of the activity.
When you create Fragment 's in code, you can dynamically manage them with the FragmentManager . You manually show,
hide, and replace fragments.
Typically you declare an XML placeholder to house your fragment. A popular choice is FrameLayout with an id. If you plan
to use a Fragment without a view (discussed later in this chapter), you don't need a placeholder location.

FragmentTransaction
Fragment transactions operate on Fragments. You can begin one by getting a reference to the FragmentManager and the
changes will take effect when you use commit() .

Adding fragment
Using add() , you supply the id of your fragment holder and a reference to the fragment you'd like created.

getSupportFragmentManager().beginTransaction()
.add( R.id.holder, new MyFrag() )
.commit();

Background fragments
Instead of using fragments to encapsulate view fragments, you can could use them to handle background processing.
To do this, you return null from onCreate() and add the fragment manually (not in XML) in the hosting activity using the
FragmentManager . It's essential to use a string tag to identify the fragment since you don't have an id associated with it.

Note: You normally use this with setRetainInstance(true) to ensure that the Fragment is not destroyed on
configuration changes.
Background fragments don't provide a view and are not attached a a holder in your layout. When adding a background
fragment to the backstack, you must give it a "tag" so you can refer to it again. Otherwise you have no way to retrieve the
fragment once the transaction is complete.

getFragmentManager().beginTransaction()
.add( new MyFrag(), "tag" )
.commit();

Backstack
You can add fragments to the backstack. To do so, just add a call to addToBackStack(true) before the commit() in your
transaction.

Lab: Add CalculatorStateFragment


Create fragment
Create CalculatorStateFragment.java . This fragment will be a background frament that will manage the state of our
calculator. Notice that we are returning a null view when creating the view.

public class CalculatorStateFragment extends Fragment


{
@Override
public View onCreateView( LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState )
{
return null;
}
}

Test fragment
Add the normal first test to our fragment file:

@RunWith (RobolectricTestRunner.class)
public class CalculatorStateFragmentTest
{
@Test
public void shouldNotBeNull() throws Exception
{
assertNotNull( new CalculatorStateFragment() );
}
}

Test activity
Now add a test to CalculatorActivity to ensure that the fragment is present. It should fail!

@Test
public void shouldHaveCalculatorStateFragment() throws Exception
{
assertNotNull( activity.getFragmentManager()
.findFragmentByTag( "calculator state" ) );
}

We're using findFragmentByTag() since this is a background fragment. When we add the fragment to the activity,
we'll use a tag so that we can reference the fragment.
Now we have a reason to write code in the activity. First time this is starting to feel like real TDD!

Add CalculatorStateFragment to CalculatorActivity


Add a new instance of the fragment to our Activity 's FragmentManager via a FragmentTransaction in onCreate() .

getFragmentManager().beginTransaction()
.add( new CalculatorStateFragment(),

CALCULATOR_STATE_FRAGMENT_TAG )
.commit();

Auto-generate a TAG for the calculator state fragment using the IDE.
Now retest - everything should pass.

Commit
Yay, time for a commit!

Instance State
When you want to save the state of view components or other things that are not stored in more permanent storage, you
would use the save and restore instance state.
Let's say you're building an application that searches for your favorite city's cuisine and you have an EditText that allows
them to enter a search term. If you rotate the device, the activity is destroyed and recreated thereby using the term that
they have already entered. It's annoying to have to reenter that term when you just did! You can preserve the user
experience by storing that value for retrieval when the view is restored.
In addition to recreating the activity on rotation, this could also be invoked if the system kills your activity to free up space
and later brings it back to the foreground. This could happen if you background the app for a phone call and then check
your email, Twitter, and Facebook then go back into your city search app.
Basically, there's no guarantees in the Android world of when your app will be killed or restored, so you want to avoid user
surprise as much as possible.

onSaveInstanceState()
This is where you'd save simple pieces of data, a String for a EditText, a value for a slider, etc. You have several built in
types that you can store, but if you want more options, you can create a class that implements Parcelable and store your
data structures to support your view.

Restore
Tied to the activity and fragment states. Can get access to the instance state in onCreate() of the activity. In fragments,
you retrieve this data in onActivityCreated() .

Chapter 7: Building the Calculator


Now that our calculator looks pretty, let's make it do something!

Calculator

Lab: Requirements & Design


To the whiteboard!
Let's sketch a diagram of how out system will work and flesh out the requirements.

Discussion Questions
What should a calculator do?
What should a calculator not do?
How do we want to design the system?
What pieces do we have, how can we use them?

User Interaction
Layout
We inflate the layout in onCreateView() . If you'd like to access it class-wide, create a field.

Click listeners
When you want a user to interaction with a piece of your UI, add OnClickListener 's to a view. You can add click listeners to
all sorts of things! In other words, anything can be a "button".
Let's start with the number keys. I like to create functions when possible! I private void configureNumberKeys() {
configureNumberKey( R.id.key1 ); // ... }

private void configureNumberKey( int id )


{
layout.findViewById( id )
.setOnClickListener( createNumberOnClickListener() );
}
private View.OnClickListener createNumberOnClickListener()
{
return new View.OnClickListener()
{
@Override
public void onClick( View view )
{
String number = ((Button) view).getText().toString();
Toast.makeText( getActivity(),
"Clicked: " + number,
Toast.LENGTH_SHORT)
.show();
}
};
}

Call configureNumberKeys() from onCreateView() .


When you run this, you should see a Toast with the text of the key that you clicked.

Post to bus
In your click listener, post an event to the bus:

postToBus( new NumberButtonEvent( number ) );

We don't have the number event, so generate one now and put it in the events package. We are passing in the number
that is displayed on the button to the event's constructor.
Our event looks like this:

public class NumberButtonEvent extends BaseEvent


{
String number;
public NumberButtonEvent( String number )
{

this.number = number;
}
public String getNumber()
{
return number;
}
}

Lab: Getting on the bus


In the last lab, we posted an event to a bus. Now let's do something with it.

Registering the bus


To start listening for Otto events we need to register. In CalculatorActivity , we register the bus in onResume() :

@Override
public void onResume()
{
super.onResume();
Log.d( TAG, "onResume()" );
getBus().register( this );
}
protected Bus getBus()
{
return CalculatorApplication.getInstance().getBus();
}

And deregister in onPause() :

@Override
protected void onPause()
{
super.onPause();
Log.d( TAG, "onPause()" );
getBus().unregister( this );
}

Reacting to an event
If your component is interested in a particular bus event, subscribe for that event type. Let's add this subscription to
CalculatorActivity and move the Toast from ButtonFragment here instead. When you run this, you should still see the

same behavior.

/**
* Handles the selection of a number.
*
* @param event - number entered
*/
@Subscribe
public void onNumberSelected( NumberButtonEvent event )
{
Toast.makeText( this,
"Clicked: " + event.getNumber(),
Toast.LENGTH_SHORT )
.show();
}

Lab: Testing
Fake Click
We can fake clicks on items using performClick() . Add the following to the ButtonFragmentTest :

@Test
public void oneShouldPostEvent() throws Exception
{
Button key1 = (Button) buttonFragment.getView()
.findViewById( R.id.key1 );
key1.performClick();
verifyNumberButtonEvent( R.string.key1 );
}

The verification for each key will look pretty similar, so let's create a function:

private void verifyNumberButtonEvent( int stringId )


{
BaseEvent event = buttonFragment.getEvent();
assertTrue( event instanceof NumberButtonEvent );
assertThat( ( (NumberButtonEvent) event ).getNumber(),
equalTo( getString( strigId ) ) );
}

We'll be defining getEvent() in the next section.

Test class
We could use dependency injection or mocking frameworks to test that the events were triggered as expected, but instead
we're going to just capture that an event happened.
Let's extend the class under test:

class TestButtonFragment extends ButtonFragment


{
private BaseEvent event;
@Override
public void postToBus( BaseEvent event )
{
this.event = event;
}
BaseEvent getEvent()
{
return event;
}
}

Notice that we're overriding the post to bus behavior and capturing it here. We use the event that was triggered for
verification in the verifyNumberButtonEvent() function.
Notice that we're getting an error when we try to override the postToBus() method. That's because it doesn't exist yet!

Base Fragment

This isn't strictly a requirement, but it's useful to have a centralized Fragment .
Let's create a base fragment so that all fragments can post to the bus easily:

public class BaseFragment extends Fragment


{
public void postToBus( BaseEvent event )
{
CalculatorApplication.postToBus( event );
}
@Override
public void onResume()
{
super.onResume();
registerWithBus();
}
@Override
public void onPause()
{
super.onPause();
unRegisterFromBus();
}
private void registerWithBus()
{
getBus().register( this );
}
private void unRegisterFromBus()
{
getBus().unregister( this );
}
protected Bus getBus()
{
return CalculatorApplication.getInstance().getBus();
}
}

We also added the registration method here so that fragments can subscribe for events they are interested in.

Update
Now update ButtonFragment to extend BaseFragment . Also update ButtonFragmentTest to use a TestButtonFragment
instead of a ButtonFragment .

Failing operator tests?


If you refactored your tests to loop through an array of numbers/operators to run your tests, you'll have to do some work
here to treat operators and numbers separately.

Lab: Routing Events


How should this diagram look? Who is responsible for what?

Make It Work
Continue to work on your calculators to make them behave how you expect a calculator behaves. I'll float around the class
to help when you get stuck.

TODO
Add operator click listeners
Handle the calculator logic as determined in class
Add clear functionality
Handle NaN and other error
Extra Credit: With a simplistic implementation of this calculator, you can use the text configured on the buttons to retrieve
the numbers and operations selected by the users. This starts to break down, however, when you introduce Japanese
characters. How would you support internationalized versions?

Lab: Device Rotation


When the device rotates, our view is not pretty. Also we're losing or altering calculator fragment state!
Let's fix it!
Relevant articles:
Recreating the activity's state
Handling runtime changes
Coordinating Activity and Fragment Lifecycles

Appendix

Tools
TODO: Where should this live? It feels a little out of place here.

IDE
You will spend most of your time in the IDE, so it makes a lot of sense to get comfortable with this tool!
Google is deprecating the usage of Eclipse + ant over time. They have forked IntelliJ to create Android Studio and have
switched their build tools to gradle.
Since this is still an emerging IDE, I prefer to use IntelliJ and maven for the best intersection of tools at the moment. Luckily
it should be fairly trivial to switch to gradle since it uses a lot of the same mechanisms of maven (but it is not trivial to switch
from ant to gradle/maven).

Dalvik Debug Monitoring Service (DDMS)


This useful tool can be used to take screenshots, manage memory usage, and track down memory leaks.

Android Debug Bridge (ADB)


This is used to shell into your Android applications, copy files from the device, push files to the device, and install
applications from the command line.

Logcat
This is the phone's log. You use this for debugging and monitoring purposes.

Maven
Maven is a dependency management system that also packages builds.

Installation
Please ensure that you have installed and configured maven. You can obtain maven here:
http://maven.apache.org/download.cgi
Once installed, run mvn -v to verify your install and $PATH configuration. The output should look something like this:

[colabug:/Users/colabug/Documents/Career/Books] mvn -v
Apache Maven 3.1.1 (0728685237757ffbf44136acec0402957f723d9a; 2013-09-17 11:22:22-0400)
Maven home: /usr/local/bin/apache-maven-3.1.1
Java version: 1.6.0_65, vendor: Apple Inc.
Java home: /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home
Default locale: en_US, platform encoding: MacRoman
OS name: "mac os x", version: "10.7.5", arch: "x86_64", family: "mac"

Configuration
Here is some of my environment set-up (zsh):

export ANDROID_HOME=/usr/bin/android-sdk-macosx
export M2_HOME=/usr/local/bin/apache-maven-3.1.1
export PATH="$ANDROID_HOME/platform-tools:$ANDROID_HOME/tools:$M2_HOME/bin:$PATH"

Dependency Management
You specify which libraries you'd like to use in the pom.xml file, which lives at the root level in your project.

<dependencies>
<!--Unit testing-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.2</version>
<scope>test</scope>
</dependency>
</dependencies>

Anything from maven central (http://maven.org) is fair game. These libraries are downloaded for you and stored away in
your ~/.m2/repository directory.
Note: It's possible to point to other repositories and/or host your own. That's outside of the scope of this class.

Building
When you run mvn clean install , you are running the entire build lifecycle, including tests. It uses the build plugins that
you specify to build a particular type of application.
It's handy for adding scripts, continuous integration, and other hooks into your build process.

Further Reading:
Maven in 5 Minutes http://maven.apache.org/guides/getting-started/maven-in-five-minutes.html

Resources
Android
Developers
Training
API Guides
API Reference
Android Open Source Project (ASOP)
Tools
Samples

Design Resources
Design
Smashing Magazine
Android Patterns
Android Niceties
Inspired UI
Android Asset Studio

Videos
Corey's Android Playlist
The Fragment Transition, Corey Latislaw
Custom Components, Chiu-Ki Chan
Beautiful Android on a Shoestring, Chiu-Ki Chan; Check out my github version
Google I/O app source

Other Resources

IntelliJ Commands
Text Handling
D - Duplicate current line
C - Copy line
X - Cut line

Coding
O - Override parent members

Code Generation
F - Create field
C - Create constant field
M - Create member
V - Create variable

Testing
T - Create test*

Navigation
B - Navigate to the source folder
N - Open file name**

Notes
* Cursor should be on the name of the class
** Camel casing shortcuts can be used

Epilogue
Now that you know the basic building blocks of Android how do you want to use this system to reach the far corners of
the planet?
Do you care about teaching local children to read? Making biking on the streets safer? Curing or tracking diseases?
Connecting farmers with market prices for their crops? Track water contaminants? Allowing people to better communicate?
Or teaching the underprivileged about technology?
What ever it is that you are passionate about, Android gives you the tools and the reach to make your aspirations a reality.
You can have an impact in whatever way is meaningful to you.
Android is the perfect vehicle to impact billions of people! What are you waiting for?

Corey Leigh Latislaw


Corey Leigh Latislaw is an Android developer and consultant by day and non-profit avenger by night as well as an
occasional international conference speaker.
She has consulted with businesses of all sizes and built their Android solutions. She has 12 apps available in the iTunes
and Google Play markets. She co-founded a food tech start-up, Bushel, that makes hyper local food accessible and social.
She is founder and organizer of the Philadelphia Google Developer Group, which operates in the fifth largest city in the US.
Corey is VP of Operations at Kids On Computers where she helps the non-profit run more effectively in order to better
serve the needs people that we serve globally. She organized and participated in the recent trip to Mexico and plans to
attend many more!
Corey is passionate about encouraging broader participation in the computing sciences, local food, the outdoors,
photography, and living in downtown Philly. She's interested in bridging the global digital divide and promoting and retaining
women in the computing fields.
You can find her at coreylatislaw.com.

Bibliography
Meier, Reto (2012-04-05). Professional Android 4 Application Development. (various) John Wiley and Sons. Kindle Edition.

Android
Sherman, J. February 18, 2014. Retrieved from http://www.digitaltrends.com/mobile/android-way-cheaper-than-ios/.
Smartphone Momentum Still Evident with Shipments Expected to Reach 1.2 Billion in 2014 and Growing 23.1% Over
2013. May 28, 2014. Retrieved from http://www.idc.com/getdoc.jsp?containerId=prUS24857114/.

Testing
TODO: Working Effectively with Legacy Code, Michael Feathers
Latislaw, C. August 3, 2012. Integrating Robolectric with IntelliJ. Retrieved from
http://chariotsolutions.com/blog/post/integrating-robolectric-with-intellij/.
Latislaw, C. August 7, 2012. Android Unit Testing With Robolectric. Retrieved from
http://chariotsolutions.com/blog/post/android-unit-testing-with-robolectric/.
Web citations: Author, A. (date). Title of document [Format description]. Retrieved from http://URL

S-ar putea să vă placă și