SlideShare a Scribd company logo
1 of 113
Download to read offline
1
2
By
Ryan Hodson
Foreword by Daniel Jebaraj
3
Copyright © 2014 by Syncfusion Inc.
2501 Aerial Center Parkway
Suite 200
Morrisville, NC 27560
USA
All rights reserved.
mportant licensing information. Please read.
This book is available for free download from www.syncfusion.com on completion of a registration form.
If you obtained this book from any other source, please register and download a free copy from
www.syncfusion.com.
This book is licensed for reading only if obtained from www.syncfusion.com.
This book is licensed strictly for personal or educational use.
Redistribution in any form is prohibited.
The authors and copyright holders provide absolutely no warranty for any information provided.
The authors and copyright holders shall not be liable for any claim, damages, or any other liability arising
from, out of, or in connection with the information in this book.
Please do not use this book if the listed terms are unacceptable.
Use shall constitute acceptance of the terms listed.
SYNCFUSION, SUCCINCTLY, DELIVER INNOVATION WITH EASE, ESSENTIAL, and .NET ESSENTIALS are the
registered trademarks of Syncfusion, Inc.
Technical Reviewer: Rui Machado
Copy Editor: Courtney Wright
Acquisitions Coordinator: Hillary Bowling, marketing coordinator, Syncfusion, Inc.
Proofreader: Morgan Cartier Weston, content producer, Syncfusion, Inc.
I
4
Table of Contents
The Story behind the Succinctly Series of Books……………………………………………………………9
About the Author.......................................................................................................................................11
Introduction ...............................................................................................................................................12
Chapter 1 Setting Up ..............................................................................................................................13
The Android SDK...................................................................................................................................13
Installation............................................................................................................................................13
Creating a Project ................................................................................................................................13
Setting Up the Emulator.......................................................................................................................16
Compiling the Application ....................................................................................................................19
Chapter 2 Hello, Android .......................................................................................................................20
App Structure Overview.........................................................................................................................20
Creating a User Interface.......................................................................................................................21
Adding a Button .....................................................................................................................................23
Defining String Resources .....................................................................................................................24
Detecting Button Input ...........................................................................................................................25
Logging Output ......................................................................................................................................26
5
Creating Another Activity .......................................................................................................................27
Linking Activities With An Intent.............................................................................................................28
Another Button .......................................................................................................................................30
Passing Data with Intents ......................................................................................................................31
Summary................................................................................................................................................34
Chapter 3 The Activity Lifecycle ...........................................................................................................35
Common Activity Transition Events .......................................................................................................37
Pressing the Power Button ..................................................................................................................37
Rotating the Device..............................................................................................................................37
Tapping the Back Button .....................................................................................................................37
Recreating Destroyed Activities.............................................................................................................38
Restoring Instance State .....................................................................................................................38
Saving Instance State..........................................................................................................................38
View States ..........................................................................................................................................39
Example Project.....................................................................................................................................39
Summary................................................................................................................................................40
Chapter 4 User Interface Layouts .........................................................................................................41
Loading an Android Project....................................................................................................................41
6
Loading Layouts.....................................................................................................................................42
Basic View Attributes .............................................................................................................................43
Size ......................................................................................................................................................43
Padding................................................................................................................................................46
Margin ..................................................................................................................................................48
Common Layouts...................................................................................................................................49
Linear Layouts .....................................................................................................................................50
Relative Layouts ..................................................................................................................................54
List and Grid Layouts...........................................................................................................................59
Nesting Layouts .....................................................................................................................................73
Summary................................................................................................................................................75
Chapter 5 User Interface Widgets.........................................................................................................76
Images ...................................................................................................................................................76
Adding Drawable Resources ...............................................................................................................77
Scaling Images ....................................................................................................................................77
Programmatically Defining the Image Source .....................................................................................78
Buttons...................................................................................................................................................78
Text Fields .............................................................................................................................................80
7
Styling Text Fields................................................................................................................................80
Editable Text Fields .............................................................................................................................82
Checkboxes ...........................................................................................................................................86
Radio Buttons ........................................................................................................................................88
Spinners.................................................................................................................................................90
Date/Time Pickers..................................................................................................................................94
Summary................................................................................................................................................96
Chapter 6 Fragments..............................................................................................................................98
Creating a Fragment............................................................................................................................100
Embedding Fragments in Activities .....................................................................................................101
Swipe Views.........................................................................................................................................102
Adding Tabs.......................................................................................................................................104
Summary..............................................................................................................................................105
Chapter 7 Application Data..................................................................................................................107
Shared Preferences.............................................................................................................................107
Internal Storage ...................................................................................................................................109
SQLite Databases................................................................................................................................110
Representing Databases ...................................................................................................................110
8
Accessing the Database ....................................................................................................................111
Inserting Rows ...................................................................................................................................112
Querying the Database......................................................................................................................112
Summary..............................................................................................................................................113
9
The Story behind the Succinctly Series
of Books
Daniel Jebaraj, Vice President
Syncfusion, Inc.
taying on the cutting edge
As many of you may know, Syncfusion is a provider of software components for the
Microsoft platform. This puts us in the exciting but challenging position of always
being on the cutting edge.
Whenever platforms or tools are shipping out of Microsoft, which seems to be about every other
week these days, we have to educate ourselves, quickly.
Information is plentiful but harder to digest
In reality, this translates into a lot of book orders, blog searches, and Twitter scans.
While more information is becoming available on the Internet and more and more books are
being published, even on topics that are relatively new, one aspect that continues to inhibit us is
the inability to find concise technology overview books.
We are usually faced with two options: read several 500+ page books or scour the web for
relevant blog posts and other articles. Just as everyone else who has a job to do and customers
to serve, we find this quite frustrating.
The Succinctly series
This frustration translated into a deep desire to produce a series of concise technical books that
would be targeted at developers working on the Microsoft platform.
We firmly believe, given the background knowledge such developers have, that most topics can
be translated into books that are between 50 and 100 pages.
This is exactly what we resolved to accomplish with the Succinctly series. Isn’t everything
wonderful born out of a deep desire to change things for the better?
The best authors, the best content
Each author was carefully chosen from a pool of talented experts who shared our vision. The
book you now hold in your hands, and the others available in this series, are a result of the
authors’ tireless work. You will find original content that is guaranteed to get you up and running
in about the time it takes to drink a few cups of coffee.
S
10
Free forever
Syncfusion will be working to produce books on several topics. The books will always be free.
Any updates we publish will also be free.
Free? What is the catch?
There is no catch here. Syncfusion has a vested interest in this effort.
As a component vendor, our unique claim has always been that we offer deeper and broader
frameworks than anyone else on the market. Developer education greatly helps us market and
sell against competing vendors who promise to “enable AJAX support with one click,” or “turn
the moon to cheese!”
Let us know what you think
If you have any topics of interest, thoughts, or feedback, please feel free to send them to us at
succinctly-series@syncfusion.com.
We sincerely hope you enjoy reading this book and that it helps you better understand the topic
of study. Thank you for reading.
Please follow us on Twitter and “Like” us on Facebook to help us spread the
word about the Succinctly series!
11
About the Author
Ryan Hodson began learning ActionScript at age 14, which eventually led to a job creating
Flash-based data visualizations for the National Center for Supercomputing Applications at the
University of Illinois. Since then, he's worked in a diverse collection of programming fields,
building everything from websites to e-publishing platforms, touch-screen thermostats, and
natural language processing tools. These experiences have led to a love of exploring new
software and a proficiency in several languages (HTML/CSS, JavaScript, PHP, MySQL, Python,
Java, Objective-C, PDF) and many frameworks (WordPress, Django, CherryPy, and the iOS
and OSX SDKs, to name a few).
In 2012, Ryan founded an independent publishing firm called RyPress and published his first
book, Ry's Friendly Guide to Git. Since then, he has worked as a freelance technical writer for
well-known software companies, including Syncfusion and Atlassian. Ryan continues to publish
high-quality software tutorials via RyPress.com.
12
Introduction
Android is an open source operating system built on top of Linux. It powers a plethora of
devices, from smart phones to tablets to gaming consoles (along with a vast array of other
consumer electronics). According to the International Data Corporation, Android had over 70
percent market share for worldwide smartphones in the last quarter of 2012, so developing for
this platform has the potential to reach a very large number of mobile users.
Figure 1: The Android Logo
Android is the main alternative to the iOS platform for mobile applications, but unlike iOS,
Android projects can easily be created using OS X, Windows, or Linux-based computers. And
since Android uses the Java programming language, developers coming from a C# background
will most likely feel more comfortable than they would with iOS’s Objective-C programming
language.
The goal of Android Programming Succinctly is to guide you through the major aspects of
Android development with friendly, concise examples. You should walk away with a solid
understanding of the necessary design patterns, frameworks, and APIs for producing a polished
Android app. If you would like to follow along with the sample code, it can be found here.
13
Chapter 1 Setting Up
Before we start writing any code, our first task is to set up a development environment. The
major components necessary for building an Android app are as follows:
 A text editor for writing your code.
 The Android framework for linking against your application code.
 The Android command-line tools for compiling your code into a working app.
 An emulator or actual device for testing your compiled application.
While it’s possible to use virtually any IDE or text editor to create apps, the easiest way to get
started with the Android platform is the official Android Software Development Kit (SDK), which
contains all of these components in a single convenient download.
The Android SDK
The Android SDK (available for OS X, Windows, and Linux) includes the Eclipse IDE with the
Android Developer Tools (ADT) plugin, along with an emulator, a graphical layout editor, and
some other useful features. This is also the development environment that we’ll be using in this
book, so go ahead and download it now so you can follow along.
Installation
After the download has completed, unzip the file and open the eclipse folder. It should contain
an Eclipse executable that you can launch to start the IDE. You’ll be prompted to select a
workspace folder, and then Eclipse should be ready to go. And that’s it for installation!
Creating a Project
Let’s jump right in by creating a new Android project. On the File menu, click New. In the
resulting wizard, select Android Application Project.
14
Figure 2: Creating a new Android project
This will prompt you for some information about your new project:
 Application Name: The name of your app. Use Hello Android for this field.
 Project Name: The name of the project directory. This should be automatically
populated with HelloAndroid, and you can leave this value as is.
 Package Name: The unique namespace for the project. Since it’s just an example app,
you can leave the default com.example.helloandroid, but you should use the reverse
domain name of your organization for real applications.
The remaining fields define important platform requirements, and you can leave them all at their
default values. Your configuration should look like the following when you’re done:
15
Figure 3: Configuring a new Android project
The next two windows ask you about some other miscellaneous details and the app’s icon. You
can leave all of them at their default values. Finally, you’ll come to the following window asking if
you want to create an activity:
16
Figure 4: Creating an initial activity
We’ll talk about activities in great detail next chapter, but all you need to know for now is that an
activity represents a single screen of your application. We want to have something to look at
initially, so make sure Create Activity is checked, then select Blank Activity to specify an
empty screen. In the next window, you can use the default MainActivity and activity_main
values for the Activity Name and Layout Name fields (again, we’ll discuss layouts in the next
chapter). Click Finish to create a brand new Eclipse project.
Setting Up the Emulator
Unfortunately, we can’t immediately compile the template project to see what it does. First, we
need to set up a device on which to test our new app. Android is designed to let you run a single
application on devices of wildly differing dimensions and capabilities, making it a very efficient
platform for porting apps from smartphones to tablets to anything in between. The Android
Virtual Device Manager included in the SDK allows you to emulate virtually any device on the
market.
17
To view the list of emulated devices, navigate to Window and select Android Virtual Device
Manager. This window makes it easy to see how your application behaves on all sorts of
Android devices, test different screen resolutions and dimensions, and experiment with various
device capabilities (e.g., hardware keyboards, cameras, storage capacity).
To create an emulated device for our project, click New... and use GalaxyNexus for the AVD
Name, then select Galaxy Nexus from the Device dropdown menu, and leave everything else
as the default. For development purposes, it’s also a good idea to check the Use Host GPU to
use your computer’s GPU, since emulating animations can be quite slow and clunky. Your
configuration should resemble the following:
Figure 5: Creating a new emulated device
18
After clicking OK, you should find your device in the Android Virtual Device Manager window.
To start the emulator, select the GalaxyNexus item, and click Start. Leave the launch options
at their default values, and click Launch. This will start spinning up the emulator, which looks
something like the following:
Figure 6: The Android device emulator
The emulator has to boot up the Android operating system (just like a real device), so you might
be staring at that Android logo for a while before the emulator is actually ready to use. When it is
finally ready, you’ll see the typical Android home screen, and you can click around to launch
apps and explore the emulated device:
Figure 7: The emulator after it’s ready to use
19
Since it takes so long to boot, you’ll want to keep the emulator running as you start writing code
(Eclipse can re-launch the application on the emulator without restarting it).
Compiling the Application
We’re finally prepared to compile the sample project. Back in Eclipse, make sure one of the
source files is selected in the Package Explorer, then click Run, select Run as, and choose
Android Application. After taking a moment to compile, you should see your first Android app
in the device emulator. As you can see, the default template contains a single text field that says
“Hello world!”
Figure 8: The compiled template project
In the next chapter, we’ll learn how to change the contents of this text field, add other UI
components, and organize a simple Android application.
20
Chapter 2 Hello, Android
In this chapter, we’ll discover the fundamental design patterns of all Android applications. We’ll
learn how to work with activities, display UI elements by editing XML layout files, handle button
clicks, and switch between activities using intent objects. We’ll also learn about best practices
for representing dimension and string values for maximum portability.
Each screen in an Android app is represented by a custom subclass of Activity. The subclass
defines the behavior of the activity, and it’s also responsible for loading user interface from an
XML layout file. Typically, this XML layout file is where the entire interface for a given activity is
defined. To display text fields, buttons, images, and other widgets to the user, all you need to do
is add XML elements to the layout file.
Intent objects are used to switch between the various activities that compose your app. For
example, when the user clicks a button to navigate to another screen, you create an Intent
object and pass the destination activity to it. Then, you “execute” the intent to tell Android to
switch to the next page. This is the general pattern for building up a multi-screen application.
This chapter explains how all these android architecture components interact using hands-on
examples. You can follow along with the empty Android project that you created in the previous
chapter, or you can view the completed code in the HelloAndroid application included with the
sample code for this book.
App Structure Overview
Let’s start by taking a look at the files and directories our template project created for us. It may
look like there are a lot of files in Eclipse’s Package Explorer, but don’t be overwhelmed—there
are only three items that you need to worry about:
AndroidManifest.xml – This file declares everything about your app that the Android
operating system needs to launch it. This includes the classes composing the application, the
permissions required by your app, meta information like the minimum Android API for your app,
and the libraries that your app depends on. This must be in the root directory of your project.
Typically, the SDK will update this file for you automatically, so you shouldn’t have to edit it
directly.
src/ – This directory contains all of your app’s source files. This is where all of your Java
source code will reside.
res/ – This folder contains application resources, which are the images, videos, and strings
that will be displayed to the user. By abstracting resources from your application code, it’s trivial
to add support for new screen resolutions, orientations, and languages.
21
The manifest and source directory are relatively straightforward, however the resource folder
calls for a bit more explanation. If you expand this folder in the Package Explorer, you’ll find
three types of subdirectories: drawable/, layout/, and values/. The drawable/ folders
contain all of the graphics for your application, which can be either image files or special XML
files defining shapes. The layout/ directory stores the UI of each screen displayed by your
application, and the values/ folder contains lists of strings that are utilized by the UI.
Now, the interesting part is what comes after the hyphen. This portion of the folder name is a
qualifier that tells the system when to use the contained resources. For example, images in
drawable-hdpi/ will be displayed when the host device has a high-density screen (~240dpi),
whereas devices with low-density screens (~120dpi) will use the images in drawable-ldpi/.
By simply placing high-resolution images and low-resolution images in the appropriate folders,
your app will be available to both types of devices with no changes to your code. Similarly, your
app can be ported to other languages by appending en, es, fr, ar, or any other language code
after the values/ subdirectory. In this way, the res/ directory makes it very easy to support
new devices and reach new audiences.
Creating a User Interface
Android apps use XML to define their user interfaces. Each XML element in a layout file
represents either a ViewGroup or a View object. ViewGroups are invisible containers for other
View objects, and their main job is to arrange child views (or nested view groups) into a
pleasing layout. View objects are visible UI components like text fields, buttons, and tables. To
configure the properties of a view or view group, you edit the attributes of the corresponding
XML element.
The template project we used comes with a default layout called activity_main.xml, which
you should find in the res/layout/ directory. When you double-click the file, ADT displays the
graphical UI editor by default. While you can use this to visually edit the underlying XML, for this
book, we’ll be directly editing the XML markup to gain an in-depth understanding of how Android
user interfaces work. To display the raw XML, click the activity_main.xml tab in the bottom-left
of Eclipse’s editing area, highlighted in orange as you can see in the following figure:
22
Figure 9: The raw XML tab for the main layout
After clicking this tab, you’ll find the XML that defines the current layout. It should look
something like the following:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
</RelativeLayout>
23
As you can see, this defines two elements: <RelativeLayout> and <TextView>.
RelativeLayout is a subclass of ViewGroup that defines the position of its children relative to
each other. TextView is a subclass of View that represents a standard text field component.
We’ll survey the most common UI elements and later in this book.
All of the attributes in the android namespace determine various properties of the associated
element. For example, android:layout_width="match_parent" makes the RelativeLayout
stretch to the same size as its parent (in this case, the main window of the app). The available
attributes and values for each type of element are listed in the documentation for the
corresponding class (e.g., View, ViewGroup, RelativeLayout, TextView). The value of
android:text is a reference to a string resource, which we’ll explain in a moment.
Adding a Button
But first, we’re going to simplify the default layout a bit and change it to a single button, centered
on the screen. Replace the existing activity_main.xml with the following:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
tools:context=".MainActivity" >
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button_next" />
</RelativeLayout>
We’ve done two things here. First, we replaced the <RelativeLayout>’s padding attributes with
android:gravity. This tells it to center all of its child views. Second, we changed the
<TextView> element to a <Button> and gave a new value to its android:text attribute.
Unfortunately, you won’t be able to compile the project to see the button just yet. Instead, you’ll
see an error message next to the android:text attribute saying something about a missing
resource, which can be seen in the following figure:
24
Defining String Resources
When designing layouts for Android, you’ll rarely want to hardcode the value of button titles,
labels, and other text fields into the layout’s XML file. Instead, you define string resources in a
separate file and link to it from within the layout. This extra layer of abstraction makes it possible
to reuse the same layout file with different string resources. For instance, you can display
shorter instructions when in portrait mode versus landscape mode, or display English, German,
Arabic, or Chinese instructions based on the device’s locale.
Figure 10: Displaying different string resources in the same layout
Whenever you want to link to any external resource, you use the following format:
@<type>/<identifier>. For example, the android:text="@string/button_text" attribute
in activity_main.xml references a string resource with an identifier of button_text. But,
since we haven’t created that resource yet, the compiler can’t find it, so it gives us an error.
Let’s fix this now.
In the res/values/ directory, open up the strings.xml file. This is the conventional place to
define strings that will be displayed to the user (the filename is actually arbitrary, as the
resource is fully defined by the contained XML). You’ll find a few <string> elements inside of a
<resource> element. Go ahead and add the following element:
25
<string name="button_next">Next Page</string>
The name attribute defines the identifier for the resource. Eclipse should stop complaining about
the missing resource, and you should now be able to successfully compile your project. In the
emulator, you should see a button in the center of the screen with Next Page as its title:
Figure 11: Adding a button to the UI
Separating UI strings from layout construction may seem like an unnecessary hassle, but once
you start working with more complicated user interfaces and want to support multiple
languages, you’ll really appreciate the convenience of having all of your strings in one place.
Detecting Button Input
So, we have a button that the user can interact with, and it even has the iconic blue highlight
when you tap it. The next step is to detect the tap. This is accomplished via the
android:onClick attribute, which tells the system to call a method of the associated activity
whenever the button is tapped. This binds the layout layer with the behavior one, as you can
see in the following figure.
26
Figure 12: Detecting button clicks with the android:onClick attribute
In activity_main.xml, change the <Button> element to the following. This will hook up the
button to the nextPage() method of MainActivity.java (which we still need to implement).
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button_next"
android:onClick="nextPage" />
Logging Output
To figure out if our button is working, let’s log a message to the console whenever the button is
tapped. Instead of Java’s conventional System.out.println(), we’ll use the Log class that is
included with the Android platform. This is the preferred way to output messages to the console
in Android apps due to its well-defined priority levels, which let you easily filter different types of
messages. The most common Log methods are listed below from highest priority to lowest:
 Log.e(String tag, String msg) – Log an error message.
 Log.w(String tag, String msg) – Log a warning message.
 Log.i(String tag, String msg) – Log an informational message.
 Log.d(String tag, String msg) – Log a debug message.
Having several levels of message logging makes it possible to filter certain messages
depending on your compile target. For example, debug messages are stripped at runtime from
production apps, making them the best choice to use during development. Errors, warnings, and
informational messages are always logged, even in production apps.
27
The first parameter of all these methods is a string that identifies the source of the log message.
You’ll typically want this to be the name of the class that’s doing the logging, and the
conventional way to define this value is with a private static final variable in the class itself. So,
in MainActivity.java, add the following line at the beginning of the class definition:
private static final String TAG = "MainActivity";
And, as with any other Java class, we need to import the Log class before we can use it, so add
the following import statements to the top of MainActivity.java (we’ll need the View class,
too):
import android.util.Log;
import android.view.View;
Then, implement the nextPage() method to output a debug message, like so:
public void nextPage(View view) {
Log.d(TAG, "Switching to next page");
}
Remember that this is the name of the method that we hooked up in activity_main.xml, so it
should get called every time the user clicks the button. Any method used as an
android:onClick target needs to have the above signature (that is, it must be public, return
void, and accept a single View object as a parameter). The parameter is a reference to the UI
component that initiated the call, which in this case is the button that the user pressed.
You should now be able to compile your project, tap the button, and see the above message in
the LogCat panel at the bottom of the IDE. This is where all log messages will be displayed
when launching your application from within Eclipse. To display the LogCat panel, click
Window, Show View, Android, and select LogCat.
Figure 13: The LogCat panel in Eclipse
Creating Another Activity
Logging is a convenient way to make sure UI components are working properly, but you’re
probably going to want most of your buttons to do more than just display a message to the
console. To extend our example, we’ll switch to another activity when the user presses the
button.
28
The first step is to create another class for the second activity. In Eclipse, press Cmd+N (or
Ctrl+N if you are on a PC) to open the New Document wizard and select Android Activity to
add a new class to the current project. Choose Blank Activity for the template. In the next
window, use SecondActivity for the Activity Name field, activity_second for Layout Name,
and Second Activity for the Title field. Your configured activity should look like the following:
Figure 14: Configuring a new Activity class
Clicking Finish will create the SecondActivity.java and activity_second.xml files, add
them to the manifest, and add a string resource defining the activity title in
res/values/strings.xml. This is everything that needs to happen for a new activity to be
ready to use.
Linking Activities With An Intent
The user experience of a single Android application is typically made up of several different
activities (e.g., browsing the user’s contact list, editing a contact, and viewing a contact are all
separate activities, but are all part of the People app). Each activity is implemented as a
completely independent component, even if they are part of the same application. This makes it
possible for any activity to be initiated by any other activity, including ones from other
applications. For example, if your application needs to add a new contact to the user’s contact
list, it can jump directly to the People app’s activity for creating new entries.
29
To glue all of these independent activities together into a coherent app, Android provides an
Intent class, which represents an arbitrary action to be performed. The general pattern is to
create an Intent object, specify the destination class, and pass in any data required for the
destination class to perform the action. The following figure shows you how the intent object
links two activities.
Figure 15: Switching from one activity to another using an Intent object
This loose-coupling between activities makes for a very modular application architecture with
flexible code reuse opportunities.
In our example, we want to create an intent inside the MainActivity class and use
SecondActivity as the destination. We’ll worry about the data passing portion at the end of the
chapter. First, import the Intent class into MainActivity.java:
import android.content.Intent;
Then, change the nextPage() method to the following:
public void nextPage(View view) {
Intent intent = new Intent(this, SecondActivity.class);
startActivity(intent);
}
After creating the intent, we can pass it to the built-in startActivity() function to execute it.
The result should be a transition to the second activity when you click the Next Page button in
the first activity. Right now, the second activity is just a static text field that says "Hello world!",
but we’ll change that in the upcoming section.
30
Another Button
In this section, we’ll add another button to the main activity, then we’ll pass the selected button
to the second activity for display. Change activity_main.xml to the following:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
tools:context=".MainActivity" >
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button_red"
android:onClick="nextPage" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button_blue"
android:onClick="nextPage" />
</LinearLayout>
Note that both buttons will call the same nextPage() method when the user taps them. This
requires two new string resources: button_red and button_blue. In strings.xml, go ahead
and add these resources:
<string name="button_red">Red Pill</string>
<string name="button_blue">Blue Pill</string>
You can delete the button_next element since we’ll no longer be using it. Before we start
passing data with Intent objects, lets make sure we can tell which button was pressed using a
simple Log message. In MainActivity.java, change the nextPage() method to the following:
public void nextPage(View view) {
Intent intent = new Intent(this, SecondActivity.class);
Button button = (Button)view;
String message = button.getText().toString();
Log.d(TAG, message);
startActivity(intent);
}
All this does is fetch the title of the button via the getText() method and displays it via a
Log.d() call. You’ll also need to import the Button class at the top of the file:
import android.widget.Button;
Now, when you compile the app, you should see two buttons in the top-left corner.
31
Figure 16: Adding another button to the main activity
When you tap one of the buttons, you should see the corresponding title displayed in the
LogCat panel.
Passing Data with Intents
Next, we’re going to pass this information along to the next activity using our existing Intent
object. You can store data in an Intent instance by calling its putExtra() method, which takes
two parameters: a name and a string. You can think of this as creating a key-value pair on the
Intent object. For example:
public void nextPage(View view) {
Intent intent = new Intent(this, SecondActivity.class);
Button button = (Button)view;
String message = button.getText().toString();
intent.putExtra(EXTRA_MESSAGE, message);
startActivity(intent);
}
The intent.putExtra(EXTRA_MESSAGE, message); line adds the button’s title to the Intent
object, which we can later retrieve via the EXTRA_MESSAGE constant. We still need to define this
constant, so be sure to include the following at the top of the MainActivity class:
public static final String EXTRA_MESSAGE =
"com.example.helloandroid.MESSAGE";
32
We’ve now successfully encoded some data to send from the main activity to the second
activity. Next, we need to allow the second activity to receive this information. This requires two
steps:
1. Get the Intent instance that was sent to the second activity.
2. Use the EXTRA_MESSAGE key to return the associated value.
To do both of these, add the following method to SecondActivity.java:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
Intent intent = getIntent();
String message = intent.getStringExtra(MainActivity.EXTRA_MESSAGE);
Log.d(TAG, message);
}
The onCreate() method is a special method defined by the Activity class. The Android
framework invokes onCreate() whenever an Activity is started, and by overriding it in
subclasses, we can add custom initialization behavior. For now, you can think of it as the
constructor method for an Activity instance, but we’ll refine this concept a little bit in the next
chapter.
The last three lines fetch the Intent data we sent from MainActivity.java and display it with
Log.d(). The getIntent() method is another method defined by the Activity class which
simply returns the Intent instance that started the activity. Then, we use the Intent class’s
getStringExtra() method to find the value associated with the
MainActivity.EXTRA_MESSAGE key. Note that defining the key as a constant in
MainActivity.java is a best practice, as it lets the compiler make sure the key is typed
correctly. There are similar methods for other data types (e.g., getFloatExtra() returns a
float value).
The above method still needs access to the Intent and Log classes, so add the following lines
to the top of SecondActivity.java:
import android.content.Intent;
import android.util.Log;
We also need to define another TAG variable in SecondActivity.java:
private static final String TAG = "MainActivity";
You should now be able to compile the project. Click either of the buttons, and have
SecondActivity log the selected button title:
33
Figure 17: Logging the selected button’s title
For completeness, let’s make the text field in SecondActivity display the value instead of just
displaying it in LogCat. First, add an id attribute to the TextView in activity_second.xml:
<TextView
android:id="@+id/selected_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
The id attribute is necessary when you want to access a UI element from elsewhere in the
application. The plus sign in @+id is only necessary when first defining the UI element (if you
wanted to reference it from another UI file, you would not need it). The selected_title portion
defines the unique ID of the element, which can be used as follows (define this in
SecondActivity.java):
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
Intent intent = getIntent();
String message = intent.getStringExtra(MainActivity.EXTRA_MESSAGE);
TextView textField = (TextView)findViewById(R.id.selected_title);
textField.setText(message);
}
The global findViewById() method is defined by the Activity class, and it returns a View
instance that has the supplied ID. Note that we have to cast the return value to a TextView so
we can use the setText() method to display the selected button. The R.id.selected_title
snippet is the conventional way to refer to UI components defined in XML files. The R class is
generated automatically when you compile your project, and the framework populates it with
constants for each element with an android:id attribute. This method of using static constants
to refer to UI elements eliminates the possibility of referencing undefined elements (e.g., from a
misspelled or omitted ID in the layout file).
Note that you’ll have to import the TextView class for the above onCreate() method to
compile:
import android.widget.TextView;
One common mistake for Android beginners is to call findViewById() before calling
setContentView(). The latter must be called first, otherwise findViewById() will return null.
34
The second view should now display either “Red Pill” or “Blue Pill” depending on which button
you tapped in the main activity page. To switch between buttons, use the Back button on the
device to return to the main page and select the one you want to test. As you can see in the
following image, selecting the Blue Pill button will display its text.
Figure 18: Displaying the selected button title in the second activity
Summary
In this chapter, we learned about the basic structure on an Android application, how to create
user interfaces with XML files, define media resources, handle user input, and switch between
activities using an Intent object. We also acquired some practical debugging skills by taking a
brief look at the Log class.
This is almost everything you need to know to develop basic Android apps. The next chapter
explains the lifecycle of an Activity in more detail, which is important to properly manage the
memory footprint of your application. The rest of this book explores the intermediate
functionality that makes apps more interactive, data-driven, and user-friendly.
35
Chapter 3 The Activity Lifecycle
Once you have the basic structure of an Android application down, the next step is to
understand the intricacies behind constructing and destroying Activity objects. We already
saw how onCreate() can be used to initialize an Activity, but this is only one aspect of
managing an activity’s lifecycle. In this chapter, we’ll learn how to minimize CPU, memory, and
battery usage, handle phone call interruptions, save user state, and switch between landscape
and portrait orientations by properly implementing an activity’s lifecycle. This is a very important
aspect of Android app development, as a failure to do so will cause your application to regularly
crash (and that’s a very bad user experience). The following figure shows you the activity
lifecycle of an application.
Figure 19: The activity lifecycle
An activity lifecycle consists of the following six states:
 Created: The activity has been created and is ready to be displayed.
 Started: The activity is visible, but the user cannot interact with it yet. This state is
typically followed immediately by the resumed state.
 Resumed: The activity is running in the foreground and the user can interact with it.
 Paused: The activity has been interrupted by a phone call or dialog message (e.g., a
low-battery alert). This often leads immediately into the stopped state. The activity is
usually still visible while paused, but obscured by a dialog so the user cannot interact
with it.
 Stopped: The activity has been moved to the background and is no longer visible, but
the instance still exists in memory. An activity can be re-launched from this state without
re-creating it.
 Destroyed: The activity has been released by the system and no longer exists. This will
happen automatically when the Android operating system deems it necessary.
36
When an activity is being created, it passes through the first three states, and when it is being
destroyed, it passes through the latter half of the states. However, this rarely happens in a
strictly linear fashion. The typical application will switch between the started, resumed, paused,
and stopped state as the user interacts with the other activities in your application and gets
interrupted by important alerts.
To manage the transitions between these states, the Activity class provides several methods.
To define custom startup and teardown behavior, all you have to do is override these methods
in an Activity subclass. All of the Activity transition methods are listed below, along with
common examples of when they should be used:
 onCreate() – Called when the activity is entering the created state. As we saw in the
last chapter, this is where you want to initialize UI elements and otherwise prepare the
activity for use.
 onStart() – Called when the activity is entering the started state. This is a good place
to load data that needs to be displayed to the user, though this can also be done in
onResume() depending on the type of data and how you’re using it.
 onResume() – Called when the activity is entering the resumed state. This is the best
place to initialize sensor input (e.g., GPS, cameras) and begin any animations required
by your user interface.
 onPause() – Called when the activity is entering the paused state. This is where you
should stop using scarce system resources (e.g., animations, GPS, cameras) to
maximize the device’s battery life and to reduce your application’s memory footprint.
This is the teardown counterpart to the onResume() method.
 onStop() – Called when the activity is entering the stopped state. This is called right
before the application enters the background, so it’s a good place to save user data that
needs to be re-used later on (e.g., an email draft). Note that onPause() can also be an
appropriate time to do this, as it is always called immediately before onStop(). Whether
you want to use onPause() or onStop() largely depends on your specific application
requirements. onStop() is the teardown counterpart to the onStart() method.
 onDestroy() – Called when the activity is entering the destroyed state. This is the last
chance you have to clean up any resources that would otherwise leak when your
application is destroyed. This is the teardown counterpart to the onCreate() method;
however, the system will automatically release class references when the activity is
destroyed, so you usually won’t need to implement onDestroy() unless you started a
background thread or created a memory buffer in onCreate().
As you can see, there is a symmetry between the above transition methods. Anything that
happens in onStart() should be undone in onStop(), and anything done in onResume()
should be undone in onPause().
When overriding any of the above methods, remember that you must call the superclass’s
version for your application to work correctly.
37
Common Activity Transition Events
If you’re feeling a little confused about all of these transitions, it might help to discuss them from
the perspective of the user. In this section, we’ve included a few of the most common events
that can trigger an activity state transition below. Again, all of these occur frequently in the
normal usage of an application, so it’s imperative to ensure that the corresponding transition
methods consume and release system resources efficiently.
Pressing the Power Button
When the user presses the device’s power button to put it in standby, the current activity will be
moved to the background (that is, it will pause, then stop). As you might expect, the opposite
process occurs when they exit standby: the current activity will start, then resume.
If you think about how many times you’ve entered standby on your own Android device while in
the middle of an activity, you’ll quickly understand how important it is to properly manage the
onPause(), onStop(), onStart(), and onResume() methods. For example, if you left the
accelerometer sensor running after the device entered standby, the user would find their battery
unexpectedly low when they turned their phone back on.
Rotating the Device
The way the Android system handles device orientation changes can be somewhat
counterintuitive, especially for new developers. When the screen rotates, the foreground activity
is actually destroyed and re-created from scratch. This is because some layouts need to load
different resources for portrait vs. landscape modes, and using the same instance is potentially
wasteful.
Tapping the Back Button
When the user taps the Back button, the operating system interprets this as no longer needing
the current activity, so it destroys it instead of just sending it to the background. This means that
if the user navigates back to the destroyed activity, it will be created from scratch. If you’re trying
to record the user’s progress in the destroyed activity, this means that you need to store that
information outside of the activity and reload it in onCreate(), onStart(), or onResume(). If
you try to store any data as instance variables, it will be lost when the activity is destroyed.
38
Recreating Destroyed Activities
An activity that is destroyed when the user taps the Back button or when it manually terminates
itself is gone forever; however, this is not the case when an activity is destroyed due to system
constraints. For example, if an activity is about to be destroyed because the Android OS needs
the memory, it first archives the instance state of the Activity in a Bundle object, saves it to
disk, and associates the Bundle with the Activity subclass.
This Bundle object can then be used to create a new Activity object with the same state as
the destroyed one. Essentially, this makes it appear as though the original Activity instance is
always in a stopped state without consuming any resources whatsoever.
Restoring Instance State
If there is an associated Bundle for an Activity, it gets passed to its onCreate() method. For
instance, if you were developing an email client and stored the email body in an instance
variable called message, your onCreate() method might look something like the following:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(savedInstanceState != null) {
// Restore the archived instance state
this.message = savedInstanceState.getString(STATE_MESSAGE);
} else {
// Initialize with default values
this.message = "Hello, World!";
}
}
This would also require the following two lines at the top of the class:
private static final String STATE_MESSAGE = "MainActivityMessageState";
public String message;
STATE_MESSAGE is a constant that defines the key to use when archiving the message instance
variable in the bundle. This is similar to the key-value pattern for storing information in an
Intent object.
Saving Instance State
To archive custom instance variables, all you need to do is override the
onSaveInstanceState() method defined by Activity. For example, to save the above
message state, you would use something like this:
39
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
savedInstanceState.putString(STATE_MESSAGE, this.message);
super.onSaveInstanceState(savedInstanceState);
}
As with the Activity state transition methods, it’s important to call the superclass version of
onSaveInstanceState() when overriding it.
View States
The Android framework will automatically save the state of the entire view hierarchy, which
means that every text field, button, and image will look exactly as it did before it was destroyed
by the system. For many activities, this is the only state that really needs to be saved—one of
the few times you’ll actually need to implement a custom onSaveInstanceState() is when the
Activity has multiple steps and the user’s progress is recorded in instance variables.
Example Project
The ActivityLifecycle-transitions project in the resource package for this book is a
simple application demonstrating all of the transition methods discussed above. It has two
activities that you can switch between, and both of them use Log.d() to inform you when they
have changed states. When you run the project in the emulator and click the buttons, you
should see the following messages in LogCat:
05-23 12:27:41.178: D/MainActivity(4042): Created Main Activity
05-23 12:27:41.178: D/MainActivity(4042): Started Main Activity
05-23 12:27:41.178: D/MainActivity(4042): Resumed Main Activity
// Click the "Next Activity" button
05-23 12:27:44.788: D/MainActivity(4042): Paused Main Activity
05-23 12:27:45.018: D/SecondActivity(4042): Created Second Activity
05-23 12:27:45.018: D/SecondActivity(4042): Started Second Activity
05-23 12:27:45.018: D/SecondActivity(4042): Resumed Second Activity
05-23 12:27:45.728: D/MainActivity(4042): Stopped Main Activity
Also notice that if you press the Power button on the emulator (which emulates the physical
power button on an actual device), you’ll see the current activity pause and then stop. You can
also see the current activity get destroyed when you press the emulator’s Back button.
Of course, you’ll generally want to do more than just log a message in onCreate(), onStart(),
and the other activity transition methods, but this project does give you a convenient place to
start experimenting with the various states of an Activity. We’ll see some more practical
versions of these methods later in the book after we learn how to create animations and save
user data.
40
Summary
In this chapter, we introduced the lifecycle on an Activity object. As the user navigates an
application, each Activity object passes through a created, started, resumed, paused,
stopped, and destroyed state, often cycling between the middle four states several times before
being destroyed. Since these state transitions happen so frequently, and mobile devices have
such scarce system resources, properly transitioning between these states is an essential
component for a satisfying user experience.
This chapter focused more on the conceptual aspects on the Activity lifecycle because the
concrete implementation of transition methods like onResume() is so application-specific. What
you should take away from this chapter is a high-level understanding of how the Android
framework manages its Activity objects. Once you understand that, it’s easy to adapt these
concepts to your real-world application requirements.
In the next two chapters, we’ll shift gears a bit and focus on configuring the front end of an
Android application. First, we’ll learn how to arrange UI elements into user-friendly layouts, then
in the following chapter, we’ll explore the API for buttons, text fields, spinners, and the other
common input controls.
41
Chapter 4 User Interface Layouts
Laying out the UI elements in each Activity is one of the most important aspects of Android
app development. It defines the appearance of an app, how you collect and display information
to your users, and how they navigate between the various activities that compose your
application.
The first chapter in Android Programming Succinctly provided a brief introduction to XML
layouts, but this chapter will take a much deeper look at Android’s built-in layout options. In this
chapter, we’ll learn how to arrange UI elements in linear, relative, and grid layouts, the common
navigation patterns recommended by Android maintainers, and we’ll even take a brief look at
how to develop device-independent layouts that can seamlessly stretch and shrink to different
dimensions.
This chapter goes hand-in-hand with the upcoming chapter, in which we’ll learn about all of the
individual UI elements. The running example for this chapter uses buttons and text fields to
demonstrate different layout functionality, but remember that you can substitute any of the UI
elements discussed in the next chapter to the same effect.
Loading an Android Project
You can follow along with the examples for this chapter from a fresh Android project, but if you
want to see the end result, you can load the UserInterfaceLayouts project contained in the
sample code for this book. To open an existing project, launch Eclipse (with the ADT plugin),
and select Import in the File menu. This will open a dialog that looks like the following figure:
42
Figure 20: Opening a project in Eclipse
Open the General folder and select Existing Projects into Workspace, then click Next. In the
next dialog, click Browse..., find the resource folder that came with this book, and open the
UserInterfaceLayouts folder. After clicking Finish, you should see the project in the Package
Explorer.
Loading Layouts
In the first chapter, we let the template load the XML layout file for us, but it’s important to
understand how this works under the hood. Fortunately, it’s also a relatively simple process.
When you compile a project, Android automatically generates a View instance from each of
your XML layout files. Like String resources, these are accessed via the special R class under
the static layout variable. For example, if you wanted to access the View instance created from
a file called activity_main.xml, you would use the following:
R.layout.activity_main
To display this View object in an Activity, all you have to do is call the setContentView()
method. The onCreate() method of the blank Activity template always contains a call to
setContentView() to load the associated view into the Activity:
43
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
Note that you can pass any View instance to setContentView(); using the generated
R.layout.activity_main object is just a useful convention for working with XML-based
layouts. If you need to replace an Activity’s content dynamically, it’s perfectly legal to call
setContentView() outside of onCreate().
Basic View Attributes
Before we start talking about Android’s built-in layout schemes, it’s important to understand how
to set the size and position of UI elements within a particular layout. The next three sections
show you how to define the dimensions, padding, and margin of a UI element using various
XML properties.
Size
To set the width of a particular UI element, all you need to do is add an
android:layout_width attribute to that element in the XML layout file. Likewise, the
android:layout_height attribute defines the height of the element. The value for either of
these parameters must be one of the following:
 wrap_content – This constant makes the element as big as it needs to be to contain its
content.
 match_parent – This constant makes the element match the width and height of the
parent element.
 An explicit dimension – Explicit dimensions can be measured in pixels (px), density-
independent pixels (dp), scaled pixels based on preferred font size (sp), inches (in), or
millimeters (mm). For example, android:layout_width="120dp" will make the element
120 device-independent pixels wide.
 A reference to a resource – Dimension resources let you abstract reusable values into a
resource file, just like we saw with strings.xml in the first chapter of this book.
Dimension resources can be accessed using the @dimen/resource_id syntax, where
resource_id is the unique ID of the resource defined in dimens.xml.
Let’s start by exploring wrap_content. Change activity_main.xml to the following and
compile the project (we’ll discuss the LinearLayout element later in this chapter):
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
44
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity"
>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Click me!" />
</LinearLayout>
You should see a single button at the top of the screen, and since we used wrap_content for
both of the dimensions, it should be just big enough to fit the “Click me!” text (with some default
padding). If you change the text, the button will expand or shrink to match. The following figure
shows you the button you have created in the activity_main.xml.
Figure 21: A Button element using the wrap_content constant for both dimensions
If you change android:layout_width and android:layout_height to match_parent, the
button will fill the entire screen, since that’s how big the parent LinearLayout is:
<Button
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Click me!" />
When you run this, it should look something like the following:
45
Figure 22: A Button element using the match_parent constant for both dimensions
If you need more control over the size of your UI elements, you can always manually define
their width and height using explicit values, like so:
<Button
android:layout_width="200dp"
android:layout_height="60dp"
android:text="Click me!" />
This makes the button 200 device-independent pixels wide by 60 device-independent pixels
high, as you can see in the following figure:
Figure 23: A Button element with an explicit width and height
46
The last option is to add an explicit dimension to dimens.xml and reference that from
activity_main.xml. This is very useful if you have many elements that need to share the
same dimension. Dimension resource references look just like string resource references,
except you use @dimen instead of @string:
<Button
android:layout_width="@dimen/button_width"
android:layout_height="@dimen/button_height"
android:text="Click me!" />
Of course, you’ll also have to add these resources to dimens.xml before you compile the
project:
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="button_width">200dp</dimen>
<dimen name="button_height">60dp</dimen>
</resources>
This will have the exact same effect as the previous snippet, but now it’s possible to reuse the
button_width and button_height values in other layouts (or for other elements in the same
layout).
It’s also worth noting that you can mix-and-match different methods for the width and height
values. For example, it’s perfectly legal to use 200dp for the width and wrap_content for the
height.
Padding
Padding is the space between an element’s content and its border. It can be defined via any of
the following attributes, all of which take an explicit dimension (e.g., 120dp) or a reference to a
resource (e.g., @dimen/button_padding):
 android:padding – Sets a uniform value for all sides of the element.
 android:paddingTop – Sets the padding for the top edge of the element.
 android:paddingBottom – Sets the padding for the bottom edge of the element.
 android:paddingLeft – Sets the padding for the left edge of the element.
 android:paddingRight – Sets the padding for the right edge of the element.
 android:paddingStart – Sets the padding for the start edge of the element.
 android:paddingEnd – Sets the padding for the end edge of the element.
47
Figure 24: Padding attributes
Padding can be added to View or ViewGroup elements. For the former, it defines the space
between the element’s contents (e.g., a button’s title text) and its border, and for the latter it
defines the space between the edge of the group and all of its child elements. For example, the
following button will have 60 device-independent pixels surrounding its title text:
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="60dp"
android:text="Click me!" />
This should result in the following:
Figure 25: A Button with 60dp padding
Next, let’s try adding some padding to the top and bottom of the containing ViewGroup (i.e., the
LinearLayout element) and making the button match the size of its parent, like so:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
48
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingTop="24dp"
android:paddingBottom="24dp"
tools:context=".MainActivity"
>
<Button
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Click me!" />
</LinearLayout>
This demonstrates that using match_parent on a child element takes the padding of the parent
into account. Notice the 24dp padding on the top and bottom of the following screenshot:
Figure 26: A Button with match_parent for its width and height and 24dp top and bottom padding in its parent
ViewGroup
Margin
An element’s margin is the space between its border and either the surrounding elements or the
edges of the parent element. It can be specified for any View or ViewGroup using the
android:layout_margin element. And, like android:padding, the top, bottom, left, right,
start, and end margins can be defined individually using android:layout_marginTop,
android:layout_marginBottom, etc.
49
Figure 27: Margin attributes
For instance, the following code creates the same result as the example from the previous
section by defining a top and bottom margin on the Button instead of top and bottom padding
on the parent LinearLayout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity"
>
<Button
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="24dp"
android:layout_marginBottom="24dp"
android:text="Click me!" />
</LinearLayout>
Common Layouts
Android provides three main ways to arrange UI elements: linear layouts, relative layouts, and
grid layouts. The first two methods use classes called LinearLayout and RelativeLayout,
respectively. These are subclasses of ViewGroup that have built-in functionality for setting the
position and size of their child View objects. Grid layouts make it easy to display one- and two-
dimensional data structures to the user, and they are slightly more complex than linear or
relative layouts. The following figure shows you the available layout elements:
50
Figure 28: The three standard Android layouts
Linear Layouts
The LinearLayout class arranges all of the contained UI elements either horizontally or
vertically. It displays each element in the same order it appears in the XML file, making it a very
simple way to create complex layouts made up of many elements.
Orientation
A LinearLayout element needs to know in which direction it should lay out its children. This is
specified via the android:orientation attribute, which can have a value of either horizontal
or vertical. A horizontal layout will have each child element stacked left-to-right (in the same
order as they appear in the source XML). For example, try changing activity_main.xml to the
following:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
tools:context=".MainActivity"
>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Click me!" />
51
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Click me!" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Click me!" />
</LinearLayout>
If you compile the project and run it in the emulator, you should see a single row of three
buttons, like the following:
Figure 29: A LinearLayout with horizontal orientation
But if you change the orientation to vertical, like so:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity"
>
...
</LinearLayout>
The three buttons will appear in a single column:
52
Figure 30: A LinearLayout with vertical orientation
Weight
You can use the same android:layout_width and android:layout_height attributes
discussed earlier this chapter to define the size of each child element, but LinearLayout also
enables another sizing option called android:layout_weight. An element’s weight determines
how much space it takes up relative to its siblings. For example, if you want three buttons to be
evenly distributed over the height of the parent LinearLayout, you could use the following:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity"
>
<Button
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:text="Click me!" />
<Button
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:text="Click me!" />
<Button
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:text="Click me!" />
53
</LinearLayout>
Note that for vertical orientations, you need to set each element’s android:layout_height
attribute to 0 so that it can be calculated automatically using the specified weight. For horizontal
orientations, you would need to set their android:layout_width to 0. Running the above code
should give you the following:
Figure 31: Evenly weighted UI elements in a vertical linear layout
You can change the weight ratios to make the buttons take up different proportions of the
screen. For example, changing the button weights to 2, 1, 1 will make the first button take up
half the screen and the other two a fourth of the screen:
54
Figure 32: Unevenly weighted UI elements in a vertical linear layout
Specifying weights instead of explicit dimensions for UI elements is a flexible way to configure
layouts, as it lets them automatically scale to match the size of the parent ViewGroup.
Relative Layouts
RelativeLayout is an alternative to LinearLayout that lets you specify where each element
should be placed with respect to the other elements in the interface. Unlike LinearLayout, the
order of the elements in the rendered interface of a RelativeLayout does not necessarily have
to match the underlying XML file. Instead, their positions are defined by specifying a relationship
to another element (e.g., “place the button to the left of the text field” or “place the button at the
bottom of its parent”). The fact that positions are defined relative to other elements makes this a
very powerful way to create pleasing UIs that expand and contract based on the screen size.
Relative To Parent
In a RelativeLayout, a UI element can be positioned with respect to its parent or with respect
to its siblings. In either case, you define the position using one of the layout attributes defined by
RelativeLayouts.LayoutParams. The attributes that position elements relative to their parent are
listed below, and all of them take a Boolean value:
 android:layout_alignParentLeft – If true, aligns the left side of the element with
the left side of its parent.
 android:layout_centerHorizontal – If true, centers the element horizontally in its
parent.
55
 android:layout_alignParentRight – If true, aligns the right side of the element with
the right side of its parent.
 android:layout_alignParentTop – If true, aligns the top of the element to the top of
its parent.
 android:layout_centerVertical – If true, centers the element vertically in its parent.
 android:layout_alignParentBottom – If true, aligns the bottom of the element to the
bottom of its parent.
 android:layout_alignParentStart – If true, aligns the start edge of the element
with the start edge of its parent.
 android:layout_alignParentEnd – If true, aligns the end edge of the element with
the end edge of its parent.
 android:layout_centerInParent – If true, centers the element horizontally and
vertically in its parent.
For example, try changing activity_main.xml to the following:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:text="Top Button" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="Middle Button" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:text="Bottom Button" />
</RelativeLayout>
This will result in a diagonal row of three buttons, as shown below:
56
Figure 33: A RelativeLayout that positions elements with respect to their parent
Note that if you change the order of the XML elements in activity_main.xml, the buttons will
still appear in the same locations. This is different than the behavior of LinearLayout, which
places each element relative to the previous one. Also notice that if you change the button
dimensions or rotate the emulator (Ctrl+F12), they will still appear in their respective locations
relative to the screen.
Relative To Siblings
Elements can also be positioned relative to each other. The attributes listed below all specify a
graphical relationship with surrounding elements, but instead of a Boolean value, they require
an ID of another element in the layout:
 android:layout_above – Positions the bottom edge of the element above the element
with the specified ID.
 android:layout_below – Positions the top edge of the element below the element with
the specified ID.
 android:layout_toLeftOf – Positions the right edge of the element to the left of the
element with the specified ID.
 android:layout_toRightOf – Positions the left edge of the element to the right of the
element with the specified ID.
 android:layout_alignBaseline – Aligns the baseline of the element with the baseline
of the element with the specified ID.
 android:layout_alignTop– Aligns the top edge of the element with the top of the
element with the specified ID.
57
 android:layout_alignBottom – Aligns the bottom edge of the element with the bottom
edge of the element with the specified ID.
 android:layout_alignLeft – Aligns the left edge of the element with the left edge of
the element with the specified ID.
 android:layout_alignRight – Aligns the right edge of the element with the right edge
of the element with the specified ID.
For example, consider the following RelativeLayout that uses relative-to-sibling attributes
instead of relative-to-parent attributes. The second and third buttons are positioned relative to
the first one, which will be located in the default top-left corner.
<Button
android:id="@+id/topButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Top Button" />
<Button
android:id="@+id/middleButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/topButton"
android:layout_toRightOf="@id/topButton"
android:text="Middle Button" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/middleButton"
android:layout_toRightOf="@id/middleButton"
android:text="Bottom Button" />
Instead of a diagonal line of buttons that spans the entire screen, this code will give you a
diagonal with all of the button corners touching:
Figure 34: A RelativeLayout that positions elements with respect to their siblings
58
Since we’re referencing them by ID, we needed to include an android:id attribute for the top
and middle buttons. Remember from the first chapter that the first time an XML element ID is
used, it needs to be declared as "@+id/foo". This plus sign usually occurs in the android:id
attribute, but it doesn’t have to—it should always be found in the first attribute that uses the ID.
In the following snippet, the android:layout_toLeftOf attributes are the first place the
middleButton and bottomButton IDs are referenced, so they need to be prefixed by a plus
sign:
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toLeftOf="@+id/middleButton"
android:layout_above="@id/middleButton"
android:text="Top Button" />
<Button
android:id="@id/middleButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toLeftOf="@+id/bottomButton"
android:layout_above="@id/bottomButton"
android:text="Middle Button" />
<Button
android:id="@id/bottomButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:text="Bottom Button" />
This use of plus signs helps reduce the number of mistyped IDs by ensuring that new IDs are
explicitly labeled as such. For example, if you were to accidentally try to reference an element
with @id/bottumButton, the compiler would let you know that there is no such element.
The above XML positions the top and middle buttons relative to the bottom one, then puts the
bottom one in the bottom-right corner of the screen. This gives you the following layout:
59
Figure 35: A RelativeLayout that positions buttons relative to elements that have not been declared yet
Also notice that you can combine the relative-to-sibling with the relative-to-parent positioning
methods. The bottom button is positioned relative to its parent (e.g.,
android:layout_alignParentRight), and the others are positioned relative to a sibling (e.g.,
android:layout_toLeftOf).
List and Grid Layouts
So far, we’ve learned how to quickly create user interfaces with LinearLayout and
RelativeLayout; however, the content of these interfaces have been entirely static—their UI
elements are hardcoded into the underlying XML file. When you want to create a user interface
using dynamic data, things get a little bit more complicated. Data-driven layouts require three
components:
 A data set
 A subclass of Adapter for converting the data items into View objects.
 A subclass of AdapterView for laying out the View objects created by the Adapter
Before you can start configuring a data-driven layout, you need some data to work with. For this
section, our data set will be a simple array of String objects, but Android also provides many
built-in classes for fetching data from text files, databases, or web services.
Next, you need an Adapter to convert the data into View objects. For example, the built-in
ArrayAdapter takes an array of objects, creates a TextView for each one, and sets its text
property to the toString() value of each object in the array. These TextView instances are
then sent to an AdapterView.
60
AdapterView is a ViewGroup subclass that replaces the LinearLayout and RelativeLayout
classes from the previous sections. Its job is to arrange the View objects provided by the
Adapter. This section explores the two most common AdapterView subclasses, ListView and
GridView, which position these views into a list or a grid, respectively.
Figure 36: Displaying a data set in a GridView using an Adapter
List Layouts
Let’s start by getting a simple ListView up and running. Since we’re no longer hardcoding UI
elements, our XML layout file is going to be very simple—all it needs is an empty ListView
element. Change activity_main.xml to the following:
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/listView"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
This ListView defines our entire XML layout—all of its UI elements will be populated
dynamically. We do, however, need to include an android:id attribute so that we can access
the ListView instance from our activity.
Next, we need to update our MainActivity class to define a data set, pass that data set to an
Adapter, and then pass that adapter to the ListView that we defined in activity_main.xml.
So, change MainActivity.java to the following:
package com.example.userinterfacelayouts;
import android.os.Bundle;
import android.app.Activity;
import android.widget.ListView;
import android.widget.ArrayAdapter;
public class MainActivity extends Activity {
@Override
61
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String[] data = new String[] { "Item 1", "Item 2", "Item 3",
"Item 4" };
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, data);
ListView listView = (ListView) findViewById(R.id.listView);
listView.setAdapter(adapter);
}
}
First, we create an array of Strings to serve as our data set and assign it to the local data
variable. Then, we create an ArrayAdapter, which generates a TextView from each String in
the array. Its constructor takes an Activity context, the ID of the prototypical TextView, and
the array of data. The android.R.layout.simple_list_item_1 snippet is a reference to one
of Android’s convenient built-in layouts. You can find the complete list in the R.layout
documentation. Next, we have to find the ListView that we added to activity_main.xml via
findViewById(), and then we need to set its adapter property to the ArrayAdapter instance
that we just configured.
You should now be able to compile the project and see the four strings in the data array
displayed as a list of TextView elements:
Figure 37: A dynamic layout generated by ListView
List layouts make it incredibly easy to work with large data sets, and the fact that you can
represent each item with any view lets you display objects that have several properties (e.g., a
list of contacts that all display an image, name, and preferred phone number).
62
Grid Layouts
Grid layouts use the same data/Adapter/AdapterView pattern as list layouts, but instead of
ListView, you use the GridView class. GridView also defines some extra configuration options
for defining the number of columns and the spacing between each grid item, most of which are
included in the following snippet. Try changing activity_main.xml to:
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/gridView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:columnWidth="100dp"
android:numColumns="auto_fit"
android:verticalSpacing="5dp"
android:horizontalSpacing="5dp"
android:stretchMode="columnWidth" />
The only change we need to make in MainActivity.java is to update the ListView
references to GridView:
package com.example.userinterfacelayouts;
import android.os.Bundle;
import android.app.Activity;
import android.widget.GridView;
import android.widget.ArrayAdapter;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String[] data = new String[] { "Item 1", "Item 2", "Item 3",
"Item 4", "Item 5", "Item 6",
"Item 7", "Item 8", "Item 9"};
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, data);
GridView gridView = (GridView) findViewById(R.id.gridView);
gridView.setAdapter(adapter);
}
}
This will give you a nice grid of text fields that are 100 device-independent pixels wide with 5
device-independent pixels between each one:
63
Figure 38: A dynamic layout generated by GridView
Handling Click Events
Of course, you’re probably going to want to allow the user to interact with the items in a
ListView or a GridView. However, because the interface generated by either of these classes
is dynamic, we can’t use the android:onClick XML attribute to call a method when the user
clicks one of the list items. Instead, we have to define a general callback function in
MainActivity.java. This can be accomplished by implementing the
AdapterView.OnItemClickListener interface, like so:
package com.example.userinterfacelayouts;
import android.os.Bundle;
import android.app.Activity;
import android.widget.GridView;
import android.widget.ArrayAdapter;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
64
String[] data = new String[] { "Item 1", "Item 2", "Item 3",
"Item 4", "Item 5", "Item 6",
"Item 7", "Item 8", "Item 9"};
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, data);
GridView gridView = (GridView) findViewById(R.id.gridView);
gridView.setAdapter(adapter);
gridView.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v,
int position, long id) {
TextView selectedView = (TextView) v;
Log.d(TAG, String.format("You clicked: %s",
selectedView.getText()));
}
});
}
}
Now, the onItemClick() method will be called every time one of the GridView’s items are
clicked. All of the relevant parameters are passed to this function as parameters: the parent
AdapterView, the View item that was clicked, its position in the data set, and its row id. The
above callback simply casts the clicked View to a TextView and displays whatever text it
contains in LogCat.
Clicks can be handled in the exact same way for ListView layouts.
Editing The Data Set
When you want to change the data that is displayed to the user at runtime, all you have to do is
edit the underlying data set and the built-in BaseAdapter class takes care of updating the user
interface accordingly. In this section, we’ll add a button to the layout so the user can add new
items to the grid, and then we’ll re-implement the onItemClick() function to remove the
selected item from the list.
First, let’s change activity_main.xml to include a button. We’ll do this by making
LinearLayout the root XML element and giving it a Button and a GridView for children:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
tools:context=".MainActivity" >
<Button
android:layout_width="match_parent"
android:layout_height="80dp"
android:text="Add Item"
android:onClick="addItem"/>
<GridView android:id="@+id/gridView"
65
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:columnWidth="100dp"
android:numColumns="auto_fit"
android:verticalSpacing="5dp"
android:horizontalSpacing="5dp"
android:stretchMode="columnWidth" />
</LinearLayout>
Notice that it’s perfectly legal to nest different layout schemes inside of each other (i.e., putting a
GridView inside of a LinearLayout). This makes it possible to create complex, dynamic user
interfaces with very little effort.
Next, we need to alter the corresponding activity to handle Add Item button clicks and remove
items when they are selected in the GridView. This will require a number of changes to
MainActivity.java:
package com.example.userinterfacelayouts;
import android.os.Bundle;
import android.app.Activity;
import android.widget.GridView;
import android.widget.ArrayAdapter;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import java.util.ArrayList;
public class MainActivity extends Activity {
private ArrayList<String> data;
private ArrayAdapter<String> adapter;
private int count;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.data = new ArrayList<String>();
this.data.add("Item 1");
this.data.add("Item 2");
this.data.add("Item 3");
this.count = 3;
adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, data);
GridView gridView = (GridView) findViewById(R.id.gridView);
gridView.setAdapter(adapter);
gridView.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v,
int position, long id) {
66
data.remove(position);
adapter.notifyDataSetChanged();
}
});
}
public void addItem(View view) {
count++;
String newItem = String.format("Item %d", count);
this.data.add(newItem);
this.adapter.notifyDataSetChanged();
}
}
First, we have to change the static String[] array that represents our data set to a mutable
ArrayList. This will allow us to add and remove items. We also have to change the data and
adapter local variables to instance variables so that we can access them outside of
onCreate(). We also added a count variable to keep track of how many items have been
created.
To remove an item from the the GridView, all we have to do is remove it from the data set with
ArrayList’s remove() method, then call adapter.notifyDataSetChanged(). This latter
method is defined by BaseAdapter, and it tells the Adapter that it needs to synchronize its
associated AdapterView items. It should be called whenever the underlying data set has
changed.
The new addItem() method is called whenever the Add Item button is clicked. First it
increments the count variable, then uses it to generate a title for the new item, adds the title to
the data set, and finally calls notifyDataSetChanged() to refresh the GridView.
Figure 39: Adding and removing items from the data set
Android programming succinctly
Android programming succinctly
Android programming succinctly
Android programming succinctly
Android programming succinctly
Android programming succinctly
Android programming succinctly
Android programming succinctly
Android programming succinctly
Android programming succinctly
Android programming succinctly
Android programming succinctly
Android programming succinctly
Android programming succinctly
Android programming succinctly
Android programming succinctly
Android programming succinctly
Android programming succinctly
Android programming succinctly
Android programming succinctly
Android programming succinctly
Android programming succinctly
Android programming succinctly
Android programming succinctly
Android programming succinctly
Android programming succinctly
Android programming succinctly
Android programming succinctly
Android programming succinctly
Android programming succinctly
Android programming succinctly
Android programming succinctly
Android programming succinctly
Android programming succinctly
Android programming succinctly
Android programming succinctly
Android programming succinctly
Android programming succinctly
Android programming succinctly
Android programming succinctly
Android programming succinctly
Android programming succinctly
Android programming succinctly
Android programming succinctly
Android programming succinctly
Android programming succinctly
Android programming succinctly

More Related Content

Viewers also liked

Learner Records Progress Report
Learner Records Progress ReportLearner Records Progress Report
Learner Records Progress ReportAngel-A Francisco
 
Fiche technique meuble de salle de bains Citterio par Allia
Fiche technique meuble de salle de bains Citterio par AlliaFiche technique meuble de salle de bains Citterio par Allia
Fiche technique meuble de salle de bains Citterio par AlliaAllia_Salle_De_Bains
 
Related jaw lesions
Related jaw lesionsRelated jaw lesions
Related jaw lesionsIAU Dent
 
بروفايل المروى الدعائي
بروفايل المروى الدعائيبروفايل المروى الدعائي
بروفايل المروى الدعائيKhalil Amr
 
Catalogue pièces détachées N2 : Lavabos, bidets, éviers, robinetterie - par A...
Catalogue pièces détachées N2 : Lavabos, bidets, éviers, robinetterie - par A...Catalogue pièces détachées N2 : Lavabos, bidets, éviers, robinetterie - par A...
Catalogue pièces détachées N2 : Lavabos, bidets, éviers, robinetterie - par A...Allia_Salle_De_Bains
 
Asia renal care taiwan business plan
Asia renal care taiwan business planAsia renal care taiwan business plan
Asia renal care taiwan business planAndrew Olsen
 
Proyecto huevos de codorniz, desarrollo para Ibagué
Proyecto huevos de codorniz, desarrollo para IbaguéProyecto huevos de codorniz, desarrollo para Ibagué
Proyecto huevos de codorniz, desarrollo para Ibaguéwilfercom
 
Semana 3 mercadotecnia por internet
Semana 3 mercadotecnia por internetSemana 3 mercadotecnia por internet
Semana 3 mercadotecnia por internetRegina Gameros
 

Viewers also liked (14)

Learner Records Progress Report
Learner Records Progress ReportLearner Records Progress Report
Learner Records Progress Report
 
софья
софьясофья
софья
 
Fiche technique meuble de salle de bains Citterio par Allia
Fiche technique meuble de salle de bains Citterio par AlliaFiche technique meuble de salle de bains Citterio par Allia
Fiche technique meuble de salle de bains Citterio par Allia
 
1
11
1
 
Related jaw lesions
Related jaw lesionsRelated jaw lesions
Related jaw lesions
 
Rrp2
Rrp2Rrp2
Rrp2
 
بروفايل المروى الدعائي
بروفايل المروى الدعائيبروفايل المروى الدعائي
بروفايل المروى الدعائي
 
Candle going
Candle goingCandle going
Candle going
 
Catalogue pièces détachées N2 : Lavabos, bidets, éviers, robinetterie - par A...
Catalogue pièces détachées N2 : Lavabos, bidets, éviers, robinetterie - par A...Catalogue pièces détachées N2 : Lavabos, bidets, éviers, robinetterie - par A...
Catalogue pièces détachées N2 : Lavabos, bidets, éviers, robinetterie - par A...
 
Asia renal care taiwan business plan
Asia renal care taiwan business planAsia renal care taiwan business plan
Asia renal care taiwan business plan
 
Business cia component 1
Business cia component 1Business cia component 1
Business cia component 1
 
Dalla Repubblica all'Impero, Ottaviano Augusto
Dalla Repubblica all'Impero, Ottaviano AugustoDalla Repubblica all'Impero, Ottaviano Augusto
Dalla Repubblica all'Impero, Ottaviano Augusto
 
Proyecto huevos de codorniz, desarrollo para Ibagué
Proyecto huevos de codorniz, desarrollo para IbaguéProyecto huevos de codorniz, desarrollo para Ibagué
Proyecto huevos de codorniz, desarrollo para Ibagué
 
Semana 3 mercadotecnia por internet
Semana 3 mercadotecnia por internetSemana 3 mercadotecnia por internet
Semana 3 mercadotecnia por internet
 

Similar to Android programming succinctly

Accounting_Succinctly.pdf
Accounting_Succinctly.pdfAccounting_Succinctly.pdf
Accounting_Succinctly.pdfssuserfd0175
 
Entity frame work_core_succinctly
Entity frame work_core_succinctlyEntity frame work_core_succinctly
Entity frame work_core_succinctlyimdurgesh
 
Objective c succinctly 2
Objective c succinctly 2Objective c succinctly 2
Objective c succinctly 2Krunal Doshi
 
Pdf succinctly
Pdf succinctlyPdf succinctly
Pdf succinctlysuhee_0425
 
Twitterbootstrap4 succinctly
Twitterbootstrap4 succinctlyTwitterbootstrap4 succinctly
Twitterbootstrap4 succinctlyimdurgesh
 
Cplusplus succinctly
Cplusplus succinctlyCplusplus succinctly
Cplusplus succinctlydev6
 
Azure functions-succinctly
Azure functions-succinctlyAzure functions-succinctly
Azure functions-succinctlyimdurgesh
 
HR Process Efficiency for Dummies
HR Process Efficiency for DummiesHR Process Efficiency for Dummies
HR Process Efficiency for DummiesLiberteks
 
Reactjs succinctly
Reactjs succinctlyReactjs succinctly
Reactjs succinctlyimdurgesh
 
Docker succinctly
Docker succinctlyDocker succinctly
Docker succinctlysoluopen
 
Linq pad succinctly
Linq pad succinctlyLinq pad succinctly
Linq pad succinctlyimdurgesh
 
Aspnet core-2-succinctly
Aspnet core-2-succinctlyAspnet core-2-succinctly
Aspnet core-2-succinctlyimdurgesh
 
Point -of-Sale Security for Dummies
Point -of-Sale Security for DummiesPoint -of-Sale Security for Dummies
Point -of-Sale Security for DummiesLiberteks
 

Similar to Android programming succinctly (20)

Accounting_Succinctly.pdf
Accounting_Succinctly.pdfAccounting_Succinctly.pdf
Accounting_Succinctly.pdf
 
Entity frame work_core_succinctly
Entity frame work_core_succinctlyEntity frame work_core_succinctly
Entity frame work_core_succinctly
 
Objective c succinctly 2
Objective c succinctly 2Objective c succinctly 2
Objective c succinctly 2
 
Pdf succinctly
Pdf succinctlyPdf succinctly
Pdf succinctly
 
Twitterbootstrap4 succinctly
Twitterbootstrap4 succinctlyTwitterbootstrap4 succinctly
Twitterbootstrap4 succinctly
 
Cplusplus succinctly
Cplusplus succinctlyCplusplus succinctly
Cplusplus succinctly
 
Azure functions-succinctly
Azure functions-succinctlyAzure functions-succinctly
Azure functions-succinctly
 
HR Process Efficiency for Dummies
HR Process Efficiency for DummiesHR Process Efficiency for Dummies
HR Process Efficiency for Dummies
 
SFDC-For-Dummies
SFDC-For-DummiesSFDC-For-Dummies
SFDC-For-Dummies
 
Knockoutjs succinctly
Knockoutjs succinctlyKnockoutjs succinctly
Knockoutjs succinctly
 
Reactjs succinctly
Reactjs succinctlyReactjs succinctly
Reactjs succinctly
 
Unit testing succinctly marc clifton
Unit testing succinctly   marc cliftonUnit testing succinctly   marc clifton
Unit testing succinctly marc clifton
 
Docker succinctly
Docker succinctlyDocker succinctly
Docker succinctly
 
Sdnfordummies
SdnfordummiesSdnfordummies
Sdnfordummies
 
Employer branding-for-dummies
Employer branding-for-dummiesEmployer branding-for-dummies
Employer branding-for-dummies
 
Linq pad succinctly
Linq pad succinctlyLinq pad succinctly
Linq pad succinctly
 
Aspnet core-2-succinctly
Aspnet core-2-succinctlyAspnet core-2-succinctly
Aspnet core-2-succinctly
 
Point -of-Sale Security for Dummies
Point -of-Sale Security for DummiesPoint -of-Sale Security for Dummies
Point -of-Sale Security for Dummies
 
Hybrid Cloud Pour Dummies
Hybrid Cloud Pour DummiesHybrid Cloud Pour Dummies
Hybrid Cloud Pour Dummies
 
Hybrid Cloud.PDF
Hybrid Cloud.PDFHybrid Cloud.PDF
Hybrid Cloud.PDF
 

More from Brianda Yuriar

Curso de-reparacion-de-telefonos-celulares
Curso de-reparacion-de-telefonos-celularesCurso de-reparacion-de-telefonos-celulares
Curso de-reparacion-de-telefonos-celularesBrianda Yuriar
 
Ejemplo de poo (código)
Ejemplo de poo (código)Ejemplo de poo (código)
Ejemplo de poo (código)Brianda Yuriar
 
Sistemas de soporte a decisiones
Sistemas de soporte a decisionesSistemas de soporte a decisiones
Sistemas de soporte a decisionesBrianda Yuriar
 
Desviación y varianza
Desviación y varianzaDesviación y varianza
Desviación y varianzaBrianda Yuriar
 
Operaciones conceptuadoras
Operaciones conceptuadorasOperaciones conceptuadoras
Operaciones conceptuadorasBrianda Yuriar
 

More from Brianda Yuriar (9)

Curso de-reparacion-de-telefonos-celulares
Curso de-reparacion-de-telefonos-celularesCurso de-reparacion-de-telefonos-celulares
Curso de-reparacion-de-telefonos-celulares
 
Ejemplo de poo (código)
Ejemplo de poo (código)Ejemplo de poo (código)
Ejemplo de poo (código)
 
Sistemas de soporte a decisiones
Sistemas de soporte a decisionesSistemas de soporte a decisiones
Sistemas de soporte a decisiones
 
Desviación y varianza
Desviación y varianzaDesviación y varianza
Desviación y varianza
 
Articulo 71 y 72
Articulo 71 y 72Articulo 71 y 72
Articulo 71 y 72
 
Sesgo
SesgoSesgo
Sesgo
 
Teoria de sistema
Teoria de sistemaTeoria de sistema
Teoria de sistema
 
Teoria de sistema
Teoria de sistemaTeoria de sistema
Teoria de sistema
 
Operaciones conceptuadoras
Operaciones conceptuadorasOperaciones conceptuadoras
Operaciones conceptuadoras
 

Recently uploaded

Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Paola De la Torre
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...shyamraj55
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
Google AI Hackathon: LLM based Evaluator for RAG
Google AI Hackathon: LLM based Evaluator for RAGGoogle AI Hackathon: LLM based Evaluator for RAG
Google AI Hackathon: LLM based Evaluator for RAGSujit Pal
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
Maximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxMaximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxOnBoard
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024Results
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure servicePooja Nehwal
 
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...HostedbyConfluent
 

Recently uploaded (20)

Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Google AI Hackathon: LLM based Evaluator for RAG
Google AI Hackathon: LLM based Evaluator for RAGGoogle AI Hackathon: LLM based Evaluator for RAG
Google AI Hackathon: LLM based Evaluator for RAG
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Maximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxMaximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptx
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
 
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
 

Android programming succinctly

  • 1. 1
  • 3. 3 Copyright © 2014 by Syncfusion Inc. 2501 Aerial Center Parkway Suite 200 Morrisville, NC 27560 USA All rights reserved. mportant licensing information. Please read. This book is available for free download from www.syncfusion.com on completion of a registration form. If you obtained this book from any other source, please register and download a free copy from www.syncfusion.com. This book is licensed for reading only if obtained from www.syncfusion.com. This book is licensed strictly for personal or educational use. Redistribution in any form is prohibited. The authors and copyright holders provide absolutely no warranty for any information provided. The authors and copyright holders shall not be liable for any claim, damages, or any other liability arising from, out of, or in connection with the information in this book. Please do not use this book if the listed terms are unacceptable. Use shall constitute acceptance of the terms listed. SYNCFUSION, SUCCINCTLY, DELIVER INNOVATION WITH EASE, ESSENTIAL, and .NET ESSENTIALS are the registered trademarks of Syncfusion, Inc. Technical Reviewer: Rui Machado Copy Editor: Courtney Wright Acquisitions Coordinator: Hillary Bowling, marketing coordinator, Syncfusion, Inc. Proofreader: Morgan Cartier Weston, content producer, Syncfusion, Inc. I
  • 4. 4 Table of Contents The Story behind the Succinctly Series of Books……………………………………………………………9 About the Author.......................................................................................................................................11 Introduction ...............................................................................................................................................12 Chapter 1 Setting Up ..............................................................................................................................13 The Android SDK...................................................................................................................................13 Installation............................................................................................................................................13 Creating a Project ................................................................................................................................13 Setting Up the Emulator.......................................................................................................................16 Compiling the Application ....................................................................................................................19 Chapter 2 Hello, Android .......................................................................................................................20 App Structure Overview.........................................................................................................................20 Creating a User Interface.......................................................................................................................21 Adding a Button .....................................................................................................................................23 Defining String Resources .....................................................................................................................24 Detecting Button Input ...........................................................................................................................25 Logging Output ......................................................................................................................................26
  • 5. 5 Creating Another Activity .......................................................................................................................27 Linking Activities With An Intent.............................................................................................................28 Another Button .......................................................................................................................................30 Passing Data with Intents ......................................................................................................................31 Summary................................................................................................................................................34 Chapter 3 The Activity Lifecycle ...........................................................................................................35 Common Activity Transition Events .......................................................................................................37 Pressing the Power Button ..................................................................................................................37 Rotating the Device..............................................................................................................................37 Tapping the Back Button .....................................................................................................................37 Recreating Destroyed Activities.............................................................................................................38 Restoring Instance State .....................................................................................................................38 Saving Instance State..........................................................................................................................38 View States ..........................................................................................................................................39 Example Project.....................................................................................................................................39 Summary................................................................................................................................................40 Chapter 4 User Interface Layouts .........................................................................................................41 Loading an Android Project....................................................................................................................41
  • 6. 6 Loading Layouts.....................................................................................................................................42 Basic View Attributes .............................................................................................................................43 Size ......................................................................................................................................................43 Padding................................................................................................................................................46 Margin ..................................................................................................................................................48 Common Layouts...................................................................................................................................49 Linear Layouts .....................................................................................................................................50 Relative Layouts ..................................................................................................................................54 List and Grid Layouts...........................................................................................................................59 Nesting Layouts .....................................................................................................................................73 Summary................................................................................................................................................75 Chapter 5 User Interface Widgets.........................................................................................................76 Images ...................................................................................................................................................76 Adding Drawable Resources ...............................................................................................................77 Scaling Images ....................................................................................................................................77 Programmatically Defining the Image Source .....................................................................................78 Buttons...................................................................................................................................................78 Text Fields .............................................................................................................................................80
  • 7. 7 Styling Text Fields................................................................................................................................80 Editable Text Fields .............................................................................................................................82 Checkboxes ...........................................................................................................................................86 Radio Buttons ........................................................................................................................................88 Spinners.................................................................................................................................................90 Date/Time Pickers..................................................................................................................................94 Summary................................................................................................................................................96 Chapter 6 Fragments..............................................................................................................................98 Creating a Fragment............................................................................................................................100 Embedding Fragments in Activities .....................................................................................................101 Swipe Views.........................................................................................................................................102 Adding Tabs.......................................................................................................................................104 Summary..............................................................................................................................................105 Chapter 7 Application Data..................................................................................................................107 Shared Preferences.............................................................................................................................107 Internal Storage ...................................................................................................................................109 SQLite Databases................................................................................................................................110 Representing Databases ...................................................................................................................110
  • 8. 8 Accessing the Database ....................................................................................................................111 Inserting Rows ...................................................................................................................................112 Querying the Database......................................................................................................................112 Summary..............................................................................................................................................113
  • 9. 9 The Story behind the Succinctly Series of Books Daniel Jebaraj, Vice President Syncfusion, Inc. taying on the cutting edge As many of you may know, Syncfusion is a provider of software components for the Microsoft platform. This puts us in the exciting but challenging position of always being on the cutting edge. Whenever platforms or tools are shipping out of Microsoft, which seems to be about every other week these days, we have to educate ourselves, quickly. Information is plentiful but harder to digest In reality, this translates into a lot of book orders, blog searches, and Twitter scans. While more information is becoming available on the Internet and more and more books are being published, even on topics that are relatively new, one aspect that continues to inhibit us is the inability to find concise technology overview books. We are usually faced with two options: read several 500+ page books or scour the web for relevant blog posts and other articles. Just as everyone else who has a job to do and customers to serve, we find this quite frustrating. The Succinctly series This frustration translated into a deep desire to produce a series of concise technical books that would be targeted at developers working on the Microsoft platform. We firmly believe, given the background knowledge such developers have, that most topics can be translated into books that are between 50 and 100 pages. This is exactly what we resolved to accomplish with the Succinctly series. Isn’t everything wonderful born out of a deep desire to change things for the better? The best authors, the best content Each author was carefully chosen from a pool of talented experts who shared our vision. The book you now hold in your hands, and the others available in this series, are a result of the authors’ tireless work. You will find original content that is guaranteed to get you up and running in about the time it takes to drink a few cups of coffee. S
  • 10. 10 Free forever Syncfusion will be working to produce books on several topics. The books will always be free. Any updates we publish will also be free. Free? What is the catch? There is no catch here. Syncfusion has a vested interest in this effort. As a component vendor, our unique claim has always been that we offer deeper and broader frameworks than anyone else on the market. Developer education greatly helps us market and sell against competing vendors who promise to “enable AJAX support with one click,” or “turn the moon to cheese!” Let us know what you think If you have any topics of interest, thoughts, or feedback, please feel free to send them to us at succinctly-series@syncfusion.com. We sincerely hope you enjoy reading this book and that it helps you better understand the topic of study. Thank you for reading. Please follow us on Twitter and “Like” us on Facebook to help us spread the word about the Succinctly series!
  • 11. 11 About the Author Ryan Hodson began learning ActionScript at age 14, which eventually led to a job creating Flash-based data visualizations for the National Center for Supercomputing Applications at the University of Illinois. Since then, he's worked in a diverse collection of programming fields, building everything from websites to e-publishing platforms, touch-screen thermostats, and natural language processing tools. These experiences have led to a love of exploring new software and a proficiency in several languages (HTML/CSS, JavaScript, PHP, MySQL, Python, Java, Objective-C, PDF) and many frameworks (WordPress, Django, CherryPy, and the iOS and OSX SDKs, to name a few). In 2012, Ryan founded an independent publishing firm called RyPress and published his first book, Ry's Friendly Guide to Git. Since then, he has worked as a freelance technical writer for well-known software companies, including Syncfusion and Atlassian. Ryan continues to publish high-quality software tutorials via RyPress.com.
  • 12. 12 Introduction Android is an open source operating system built on top of Linux. It powers a plethora of devices, from smart phones to tablets to gaming consoles (along with a vast array of other consumer electronics). According to the International Data Corporation, Android had over 70 percent market share for worldwide smartphones in the last quarter of 2012, so developing for this platform has the potential to reach a very large number of mobile users. Figure 1: The Android Logo Android is the main alternative to the iOS platform for mobile applications, but unlike iOS, Android projects can easily be created using OS X, Windows, or Linux-based computers. And since Android uses the Java programming language, developers coming from a C# background will most likely feel more comfortable than they would with iOS’s Objective-C programming language. The goal of Android Programming Succinctly is to guide you through the major aspects of Android development with friendly, concise examples. You should walk away with a solid understanding of the necessary design patterns, frameworks, and APIs for producing a polished Android app. If you would like to follow along with the sample code, it can be found here.
  • 13. 13 Chapter 1 Setting Up Before we start writing any code, our first task is to set up a development environment. The major components necessary for building an Android app are as follows:  A text editor for writing your code.  The Android framework for linking against your application code.  The Android command-line tools for compiling your code into a working app.  An emulator or actual device for testing your compiled application. While it’s possible to use virtually any IDE or text editor to create apps, the easiest way to get started with the Android platform is the official Android Software Development Kit (SDK), which contains all of these components in a single convenient download. The Android SDK The Android SDK (available for OS X, Windows, and Linux) includes the Eclipse IDE with the Android Developer Tools (ADT) plugin, along with an emulator, a graphical layout editor, and some other useful features. This is also the development environment that we’ll be using in this book, so go ahead and download it now so you can follow along. Installation After the download has completed, unzip the file and open the eclipse folder. It should contain an Eclipse executable that you can launch to start the IDE. You’ll be prompted to select a workspace folder, and then Eclipse should be ready to go. And that’s it for installation! Creating a Project Let’s jump right in by creating a new Android project. On the File menu, click New. In the resulting wizard, select Android Application Project.
  • 14. 14 Figure 2: Creating a new Android project This will prompt you for some information about your new project:  Application Name: The name of your app. Use Hello Android for this field.  Project Name: The name of the project directory. This should be automatically populated with HelloAndroid, and you can leave this value as is.  Package Name: The unique namespace for the project. Since it’s just an example app, you can leave the default com.example.helloandroid, but you should use the reverse domain name of your organization for real applications. The remaining fields define important platform requirements, and you can leave them all at their default values. Your configuration should look like the following when you’re done:
  • 15. 15 Figure 3: Configuring a new Android project The next two windows ask you about some other miscellaneous details and the app’s icon. You can leave all of them at their default values. Finally, you’ll come to the following window asking if you want to create an activity:
  • 16. 16 Figure 4: Creating an initial activity We’ll talk about activities in great detail next chapter, but all you need to know for now is that an activity represents a single screen of your application. We want to have something to look at initially, so make sure Create Activity is checked, then select Blank Activity to specify an empty screen. In the next window, you can use the default MainActivity and activity_main values for the Activity Name and Layout Name fields (again, we’ll discuss layouts in the next chapter). Click Finish to create a brand new Eclipse project. Setting Up the Emulator Unfortunately, we can’t immediately compile the template project to see what it does. First, we need to set up a device on which to test our new app. Android is designed to let you run a single application on devices of wildly differing dimensions and capabilities, making it a very efficient platform for porting apps from smartphones to tablets to anything in between. The Android Virtual Device Manager included in the SDK allows you to emulate virtually any device on the market.
  • 17. 17 To view the list of emulated devices, navigate to Window and select Android Virtual Device Manager. This window makes it easy to see how your application behaves on all sorts of Android devices, test different screen resolutions and dimensions, and experiment with various device capabilities (e.g., hardware keyboards, cameras, storage capacity). To create an emulated device for our project, click New... and use GalaxyNexus for the AVD Name, then select Galaxy Nexus from the Device dropdown menu, and leave everything else as the default. For development purposes, it’s also a good idea to check the Use Host GPU to use your computer’s GPU, since emulating animations can be quite slow and clunky. Your configuration should resemble the following: Figure 5: Creating a new emulated device
  • 18. 18 After clicking OK, you should find your device in the Android Virtual Device Manager window. To start the emulator, select the GalaxyNexus item, and click Start. Leave the launch options at their default values, and click Launch. This will start spinning up the emulator, which looks something like the following: Figure 6: The Android device emulator The emulator has to boot up the Android operating system (just like a real device), so you might be staring at that Android logo for a while before the emulator is actually ready to use. When it is finally ready, you’ll see the typical Android home screen, and you can click around to launch apps and explore the emulated device: Figure 7: The emulator after it’s ready to use
  • 19. 19 Since it takes so long to boot, you’ll want to keep the emulator running as you start writing code (Eclipse can re-launch the application on the emulator without restarting it). Compiling the Application We’re finally prepared to compile the sample project. Back in Eclipse, make sure one of the source files is selected in the Package Explorer, then click Run, select Run as, and choose Android Application. After taking a moment to compile, you should see your first Android app in the device emulator. As you can see, the default template contains a single text field that says “Hello world!” Figure 8: The compiled template project In the next chapter, we’ll learn how to change the contents of this text field, add other UI components, and organize a simple Android application.
  • 20. 20 Chapter 2 Hello, Android In this chapter, we’ll discover the fundamental design patterns of all Android applications. We’ll learn how to work with activities, display UI elements by editing XML layout files, handle button clicks, and switch between activities using intent objects. We’ll also learn about best practices for representing dimension and string values for maximum portability. Each screen in an Android app is represented by a custom subclass of Activity. The subclass defines the behavior of the activity, and it’s also responsible for loading user interface from an XML layout file. Typically, this XML layout file is where the entire interface for a given activity is defined. To display text fields, buttons, images, and other widgets to the user, all you need to do is add XML elements to the layout file. Intent objects are used to switch between the various activities that compose your app. For example, when the user clicks a button to navigate to another screen, you create an Intent object and pass the destination activity to it. Then, you “execute” the intent to tell Android to switch to the next page. This is the general pattern for building up a multi-screen application. This chapter explains how all these android architecture components interact using hands-on examples. You can follow along with the empty Android project that you created in the previous chapter, or you can view the completed code in the HelloAndroid application included with the sample code for this book. App Structure Overview Let’s start by taking a look at the files and directories our template project created for us. It may look like there are a lot of files in Eclipse’s Package Explorer, but don’t be overwhelmed—there are only three items that you need to worry about: AndroidManifest.xml – This file declares everything about your app that the Android operating system needs to launch it. This includes the classes composing the application, the permissions required by your app, meta information like the minimum Android API for your app, and the libraries that your app depends on. This must be in the root directory of your project. Typically, the SDK will update this file for you automatically, so you shouldn’t have to edit it directly. src/ – This directory contains all of your app’s source files. This is where all of your Java source code will reside. res/ – This folder contains application resources, which are the images, videos, and strings that will be displayed to the user. By abstracting resources from your application code, it’s trivial to add support for new screen resolutions, orientations, and languages.
  • 21. 21 The manifest and source directory are relatively straightforward, however the resource folder calls for a bit more explanation. If you expand this folder in the Package Explorer, you’ll find three types of subdirectories: drawable/, layout/, and values/. The drawable/ folders contain all of the graphics for your application, which can be either image files or special XML files defining shapes. The layout/ directory stores the UI of each screen displayed by your application, and the values/ folder contains lists of strings that are utilized by the UI. Now, the interesting part is what comes after the hyphen. This portion of the folder name is a qualifier that tells the system when to use the contained resources. For example, images in drawable-hdpi/ will be displayed when the host device has a high-density screen (~240dpi), whereas devices with low-density screens (~120dpi) will use the images in drawable-ldpi/. By simply placing high-resolution images and low-resolution images in the appropriate folders, your app will be available to both types of devices with no changes to your code. Similarly, your app can be ported to other languages by appending en, es, fr, ar, or any other language code after the values/ subdirectory. In this way, the res/ directory makes it very easy to support new devices and reach new audiences. Creating a User Interface Android apps use XML to define their user interfaces. Each XML element in a layout file represents either a ViewGroup or a View object. ViewGroups are invisible containers for other View objects, and their main job is to arrange child views (or nested view groups) into a pleasing layout. View objects are visible UI components like text fields, buttons, and tables. To configure the properties of a view or view group, you edit the attributes of the corresponding XML element. The template project we used comes with a default layout called activity_main.xml, which you should find in the res/layout/ directory. When you double-click the file, ADT displays the graphical UI editor by default. While you can use this to visually edit the underlying XML, for this book, we’ll be directly editing the XML markup to gain an in-depth understanding of how Android user interfaces work. To display the raw XML, click the activity_main.xml tab in the bottom-left of Eclipse’s editing area, highlighted in orange as you can see in the following figure:
  • 22. 22 Figure 9: The raw XML tab for the main layout After clicking this tab, you’ll find the XML that defines the current layout. It should look something like the following: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/hello_world" /> </RelativeLayout>
  • 23. 23 As you can see, this defines two elements: <RelativeLayout> and <TextView>. RelativeLayout is a subclass of ViewGroup that defines the position of its children relative to each other. TextView is a subclass of View that represents a standard text field component. We’ll survey the most common UI elements and later in this book. All of the attributes in the android namespace determine various properties of the associated element. For example, android:layout_width="match_parent" makes the RelativeLayout stretch to the same size as its parent (in this case, the main window of the app). The available attributes and values for each type of element are listed in the documentation for the corresponding class (e.g., View, ViewGroup, RelativeLayout, TextView). The value of android:text is a reference to a string resource, which we’ll explain in a moment. Adding a Button But first, we’re going to simplify the default layout a bit and change it to a single button, centered on the screen. Replace the existing activity_main.xml with the following: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" tools:context=".MainActivity" > <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/button_next" /> </RelativeLayout> We’ve done two things here. First, we replaced the <RelativeLayout>’s padding attributes with android:gravity. This tells it to center all of its child views. Second, we changed the <TextView> element to a <Button> and gave a new value to its android:text attribute. Unfortunately, you won’t be able to compile the project to see the button just yet. Instead, you’ll see an error message next to the android:text attribute saying something about a missing resource, which can be seen in the following figure:
  • 24. 24 Defining String Resources When designing layouts for Android, you’ll rarely want to hardcode the value of button titles, labels, and other text fields into the layout’s XML file. Instead, you define string resources in a separate file and link to it from within the layout. This extra layer of abstraction makes it possible to reuse the same layout file with different string resources. For instance, you can display shorter instructions when in portrait mode versus landscape mode, or display English, German, Arabic, or Chinese instructions based on the device’s locale. Figure 10: Displaying different string resources in the same layout Whenever you want to link to any external resource, you use the following format: @<type>/<identifier>. For example, the android:text="@string/button_text" attribute in activity_main.xml references a string resource with an identifier of button_text. But, since we haven’t created that resource yet, the compiler can’t find it, so it gives us an error. Let’s fix this now. In the res/values/ directory, open up the strings.xml file. This is the conventional place to define strings that will be displayed to the user (the filename is actually arbitrary, as the resource is fully defined by the contained XML). You’ll find a few <string> elements inside of a <resource> element. Go ahead and add the following element:
  • 25. 25 <string name="button_next">Next Page</string> The name attribute defines the identifier for the resource. Eclipse should stop complaining about the missing resource, and you should now be able to successfully compile your project. In the emulator, you should see a button in the center of the screen with Next Page as its title: Figure 11: Adding a button to the UI Separating UI strings from layout construction may seem like an unnecessary hassle, but once you start working with more complicated user interfaces and want to support multiple languages, you’ll really appreciate the convenience of having all of your strings in one place. Detecting Button Input So, we have a button that the user can interact with, and it even has the iconic blue highlight when you tap it. The next step is to detect the tap. This is accomplished via the android:onClick attribute, which tells the system to call a method of the associated activity whenever the button is tapped. This binds the layout layer with the behavior one, as you can see in the following figure.
  • 26. 26 Figure 12: Detecting button clicks with the android:onClick attribute In activity_main.xml, change the <Button> element to the following. This will hook up the button to the nextPage() method of MainActivity.java (which we still need to implement). <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/button_next" android:onClick="nextPage" /> Logging Output To figure out if our button is working, let’s log a message to the console whenever the button is tapped. Instead of Java’s conventional System.out.println(), we’ll use the Log class that is included with the Android platform. This is the preferred way to output messages to the console in Android apps due to its well-defined priority levels, which let you easily filter different types of messages. The most common Log methods are listed below from highest priority to lowest:  Log.e(String tag, String msg) – Log an error message.  Log.w(String tag, String msg) – Log a warning message.  Log.i(String tag, String msg) – Log an informational message.  Log.d(String tag, String msg) – Log a debug message. Having several levels of message logging makes it possible to filter certain messages depending on your compile target. For example, debug messages are stripped at runtime from production apps, making them the best choice to use during development. Errors, warnings, and informational messages are always logged, even in production apps.
  • 27. 27 The first parameter of all these methods is a string that identifies the source of the log message. You’ll typically want this to be the name of the class that’s doing the logging, and the conventional way to define this value is with a private static final variable in the class itself. So, in MainActivity.java, add the following line at the beginning of the class definition: private static final String TAG = "MainActivity"; And, as with any other Java class, we need to import the Log class before we can use it, so add the following import statements to the top of MainActivity.java (we’ll need the View class, too): import android.util.Log; import android.view.View; Then, implement the nextPage() method to output a debug message, like so: public void nextPage(View view) { Log.d(TAG, "Switching to next page"); } Remember that this is the name of the method that we hooked up in activity_main.xml, so it should get called every time the user clicks the button. Any method used as an android:onClick target needs to have the above signature (that is, it must be public, return void, and accept a single View object as a parameter). The parameter is a reference to the UI component that initiated the call, which in this case is the button that the user pressed. You should now be able to compile your project, tap the button, and see the above message in the LogCat panel at the bottom of the IDE. This is where all log messages will be displayed when launching your application from within Eclipse. To display the LogCat panel, click Window, Show View, Android, and select LogCat. Figure 13: The LogCat panel in Eclipse Creating Another Activity Logging is a convenient way to make sure UI components are working properly, but you’re probably going to want most of your buttons to do more than just display a message to the console. To extend our example, we’ll switch to another activity when the user presses the button.
  • 28. 28 The first step is to create another class for the second activity. In Eclipse, press Cmd+N (or Ctrl+N if you are on a PC) to open the New Document wizard and select Android Activity to add a new class to the current project. Choose Blank Activity for the template. In the next window, use SecondActivity for the Activity Name field, activity_second for Layout Name, and Second Activity for the Title field. Your configured activity should look like the following: Figure 14: Configuring a new Activity class Clicking Finish will create the SecondActivity.java and activity_second.xml files, add them to the manifest, and add a string resource defining the activity title in res/values/strings.xml. This is everything that needs to happen for a new activity to be ready to use. Linking Activities With An Intent The user experience of a single Android application is typically made up of several different activities (e.g., browsing the user’s contact list, editing a contact, and viewing a contact are all separate activities, but are all part of the People app). Each activity is implemented as a completely independent component, even if they are part of the same application. This makes it possible for any activity to be initiated by any other activity, including ones from other applications. For example, if your application needs to add a new contact to the user’s contact list, it can jump directly to the People app’s activity for creating new entries.
  • 29. 29 To glue all of these independent activities together into a coherent app, Android provides an Intent class, which represents an arbitrary action to be performed. The general pattern is to create an Intent object, specify the destination class, and pass in any data required for the destination class to perform the action. The following figure shows you how the intent object links two activities. Figure 15: Switching from one activity to another using an Intent object This loose-coupling between activities makes for a very modular application architecture with flexible code reuse opportunities. In our example, we want to create an intent inside the MainActivity class and use SecondActivity as the destination. We’ll worry about the data passing portion at the end of the chapter. First, import the Intent class into MainActivity.java: import android.content.Intent; Then, change the nextPage() method to the following: public void nextPage(View view) { Intent intent = new Intent(this, SecondActivity.class); startActivity(intent); } After creating the intent, we can pass it to the built-in startActivity() function to execute it. The result should be a transition to the second activity when you click the Next Page button in the first activity. Right now, the second activity is just a static text field that says "Hello world!", but we’ll change that in the upcoming section.
  • 30. 30 Another Button In this section, we’ll add another button to the main activity, then we’ll pass the selected button to the second activity for display. Change activity_main.xml to the following: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" tools:context=".MainActivity" > <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/button_red" android:onClick="nextPage" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/button_blue" android:onClick="nextPage" /> </LinearLayout> Note that both buttons will call the same nextPage() method when the user taps them. This requires two new string resources: button_red and button_blue. In strings.xml, go ahead and add these resources: <string name="button_red">Red Pill</string> <string name="button_blue">Blue Pill</string> You can delete the button_next element since we’ll no longer be using it. Before we start passing data with Intent objects, lets make sure we can tell which button was pressed using a simple Log message. In MainActivity.java, change the nextPage() method to the following: public void nextPage(View view) { Intent intent = new Intent(this, SecondActivity.class); Button button = (Button)view; String message = button.getText().toString(); Log.d(TAG, message); startActivity(intent); } All this does is fetch the title of the button via the getText() method and displays it via a Log.d() call. You’ll also need to import the Button class at the top of the file: import android.widget.Button; Now, when you compile the app, you should see two buttons in the top-left corner.
  • 31. 31 Figure 16: Adding another button to the main activity When you tap one of the buttons, you should see the corresponding title displayed in the LogCat panel. Passing Data with Intents Next, we’re going to pass this information along to the next activity using our existing Intent object. You can store data in an Intent instance by calling its putExtra() method, which takes two parameters: a name and a string. You can think of this as creating a key-value pair on the Intent object. For example: public void nextPage(View view) { Intent intent = new Intent(this, SecondActivity.class); Button button = (Button)view; String message = button.getText().toString(); intent.putExtra(EXTRA_MESSAGE, message); startActivity(intent); } The intent.putExtra(EXTRA_MESSAGE, message); line adds the button’s title to the Intent object, which we can later retrieve via the EXTRA_MESSAGE constant. We still need to define this constant, so be sure to include the following at the top of the MainActivity class: public static final String EXTRA_MESSAGE = "com.example.helloandroid.MESSAGE";
  • 32. 32 We’ve now successfully encoded some data to send from the main activity to the second activity. Next, we need to allow the second activity to receive this information. This requires two steps: 1. Get the Intent instance that was sent to the second activity. 2. Use the EXTRA_MESSAGE key to return the associated value. To do both of these, add the following method to SecondActivity.java: @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); Intent intent = getIntent(); String message = intent.getStringExtra(MainActivity.EXTRA_MESSAGE); Log.d(TAG, message); } The onCreate() method is a special method defined by the Activity class. The Android framework invokes onCreate() whenever an Activity is started, and by overriding it in subclasses, we can add custom initialization behavior. For now, you can think of it as the constructor method for an Activity instance, but we’ll refine this concept a little bit in the next chapter. The last three lines fetch the Intent data we sent from MainActivity.java and display it with Log.d(). The getIntent() method is another method defined by the Activity class which simply returns the Intent instance that started the activity. Then, we use the Intent class’s getStringExtra() method to find the value associated with the MainActivity.EXTRA_MESSAGE key. Note that defining the key as a constant in MainActivity.java is a best practice, as it lets the compiler make sure the key is typed correctly. There are similar methods for other data types (e.g., getFloatExtra() returns a float value). The above method still needs access to the Intent and Log classes, so add the following lines to the top of SecondActivity.java: import android.content.Intent; import android.util.Log; We also need to define another TAG variable in SecondActivity.java: private static final String TAG = "MainActivity"; You should now be able to compile the project. Click either of the buttons, and have SecondActivity log the selected button title:
  • 33. 33 Figure 17: Logging the selected button’s title For completeness, let’s make the text field in SecondActivity display the value instead of just displaying it in LogCat. First, add an id attribute to the TextView in activity_second.xml: <TextView android:id="@+id/selected_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/hello_world" /> The id attribute is necessary when you want to access a UI element from elsewhere in the application. The plus sign in @+id is only necessary when first defining the UI element (if you wanted to reference it from another UI file, you would not need it). The selected_title portion defines the unique ID of the element, which can be used as follows (define this in SecondActivity.java): protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); Intent intent = getIntent(); String message = intent.getStringExtra(MainActivity.EXTRA_MESSAGE); TextView textField = (TextView)findViewById(R.id.selected_title); textField.setText(message); } The global findViewById() method is defined by the Activity class, and it returns a View instance that has the supplied ID. Note that we have to cast the return value to a TextView so we can use the setText() method to display the selected button. The R.id.selected_title snippet is the conventional way to refer to UI components defined in XML files. The R class is generated automatically when you compile your project, and the framework populates it with constants for each element with an android:id attribute. This method of using static constants to refer to UI elements eliminates the possibility of referencing undefined elements (e.g., from a misspelled or omitted ID in the layout file). Note that you’ll have to import the TextView class for the above onCreate() method to compile: import android.widget.TextView; One common mistake for Android beginners is to call findViewById() before calling setContentView(). The latter must be called first, otherwise findViewById() will return null.
  • 34. 34 The second view should now display either “Red Pill” or “Blue Pill” depending on which button you tapped in the main activity page. To switch between buttons, use the Back button on the device to return to the main page and select the one you want to test. As you can see in the following image, selecting the Blue Pill button will display its text. Figure 18: Displaying the selected button title in the second activity Summary In this chapter, we learned about the basic structure on an Android application, how to create user interfaces with XML files, define media resources, handle user input, and switch between activities using an Intent object. We also acquired some practical debugging skills by taking a brief look at the Log class. This is almost everything you need to know to develop basic Android apps. The next chapter explains the lifecycle of an Activity in more detail, which is important to properly manage the memory footprint of your application. The rest of this book explores the intermediate functionality that makes apps more interactive, data-driven, and user-friendly.
  • 35. 35 Chapter 3 The Activity Lifecycle Once you have the basic structure of an Android application down, the next step is to understand the intricacies behind constructing and destroying Activity objects. We already saw how onCreate() can be used to initialize an Activity, but this is only one aspect of managing an activity’s lifecycle. In this chapter, we’ll learn how to minimize CPU, memory, and battery usage, handle phone call interruptions, save user state, and switch between landscape and portrait orientations by properly implementing an activity’s lifecycle. This is a very important aspect of Android app development, as a failure to do so will cause your application to regularly crash (and that’s a very bad user experience). The following figure shows you the activity lifecycle of an application. Figure 19: The activity lifecycle An activity lifecycle consists of the following six states:  Created: The activity has been created and is ready to be displayed.  Started: The activity is visible, but the user cannot interact with it yet. This state is typically followed immediately by the resumed state.  Resumed: The activity is running in the foreground and the user can interact with it.  Paused: The activity has been interrupted by a phone call or dialog message (e.g., a low-battery alert). This often leads immediately into the stopped state. The activity is usually still visible while paused, but obscured by a dialog so the user cannot interact with it.  Stopped: The activity has been moved to the background and is no longer visible, but the instance still exists in memory. An activity can be re-launched from this state without re-creating it.  Destroyed: The activity has been released by the system and no longer exists. This will happen automatically when the Android operating system deems it necessary.
  • 36. 36 When an activity is being created, it passes through the first three states, and when it is being destroyed, it passes through the latter half of the states. However, this rarely happens in a strictly linear fashion. The typical application will switch between the started, resumed, paused, and stopped state as the user interacts with the other activities in your application and gets interrupted by important alerts. To manage the transitions between these states, the Activity class provides several methods. To define custom startup and teardown behavior, all you have to do is override these methods in an Activity subclass. All of the Activity transition methods are listed below, along with common examples of when they should be used:  onCreate() – Called when the activity is entering the created state. As we saw in the last chapter, this is where you want to initialize UI elements and otherwise prepare the activity for use.  onStart() – Called when the activity is entering the started state. This is a good place to load data that needs to be displayed to the user, though this can also be done in onResume() depending on the type of data and how you’re using it.  onResume() – Called when the activity is entering the resumed state. This is the best place to initialize sensor input (e.g., GPS, cameras) and begin any animations required by your user interface.  onPause() – Called when the activity is entering the paused state. This is where you should stop using scarce system resources (e.g., animations, GPS, cameras) to maximize the device’s battery life and to reduce your application’s memory footprint. This is the teardown counterpart to the onResume() method.  onStop() – Called when the activity is entering the stopped state. This is called right before the application enters the background, so it’s a good place to save user data that needs to be re-used later on (e.g., an email draft). Note that onPause() can also be an appropriate time to do this, as it is always called immediately before onStop(). Whether you want to use onPause() or onStop() largely depends on your specific application requirements. onStop() is the teardown counterpart to the onStart() method.  onDestroy() – Called when the activity is entering the destroyed state. This is the last chance you have to clean up any resources that would otherwise leak when your application is destroyed. This is the teardown counterpart to the onCreate() method; however, the system will automatically release class references when the activity is destroyed, so you usually won’t need to implement onDestroy() unless you started a background thread or created a memory buffer in onCreate(). As you can see, there is a symmetry between the above transition methods. Anything that happens in onStart() should be undone in onStop(), and anything done in onResume() should be undone in onPause(). When overriding any of the above methods, remember that you must call the superclass’s version for your application to work correctly.
  • 37. 37 Common Activity Transition Events If you’re feeling a little confused about all of these transitions, it might help to discuss them from the perspective of the user. In this section, we’ve included a few of the most common events that can trigger an activity state transition below. Again, all of these occur frequently in the normal usage of an application, so it’s imperative to ensure that the corresponding transition methods consume and release system resources efficiently. Pressing the Power Button When the user presses the device’s power button to put it in standby, the current activity will be moved to the background (that is, it will pause, then stop). As you might expect, the opposite process occurs when they exit standby: the current activity will start, then resume. If you think about how many times you’ve entered standby on your own Android device while in the middle of an activity, you’ll quickly understand how important it is to properly manage the onPause(), onStop(), onStart(), and onResume() methods. For example, if you left the accelerometer sensor running after the device entered standby, the user would find their battery unexpectedly low when they turned their phone back on. Rotating the Device The way the Android system handles device orientation changes can be somewhat counterintuitive, especially for new developers. When the screen rotates, the foreground activity is actually destroyed and re-created from scratch. This is because some layouts need to load different resources for portrait vs. landscape modes, and using the same instance is potentially wasteful. Tapping the Back Button When the user taps the Back button, the operating system interprets this as no longer needing the current activity, so it destroys it instead of just sending it to the background. This means that if the user navigates back to the destroyed activity, it will be created from scratch. If you’re trying to record the user’s progress in the destroyed activity, this means that you need to store that information outside of the activity and reload it in onCreate(), onStart(), or onResume(). If you try to store any data as instance variables, it will be lost when the activity is destroyed.
  • 38. 38 Recreating Destroyed Activities An activity that is destroyed when the user taps the Back button or when it manually terminates itself is gone forever; however, this is not the case when an activity is destroyed due to system constraints. For example, if an activity is about to be destroyed because the Android OS needs the memory, it first archives the instance state of the Activity in a Bundle object, saves it to disk, and associates the Bundle with the Activity subclass. This Bundle object can then be used to create a new Activity object with the same state as the destroyed one. Essentially, this makes it appear as though the original Activity instance is always in a stopped state without consuming any resources whatsoever. Restoring Instance State If there is an associated Bundle for an Activity, it gets passed to its onCreate() method. For instance, if you were developing an email client and stored the email body in an instance variable called message, your onCreate() method might look something like the following: @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if(savedInstanceState != null) { // Restore the archived instance state this.message = savedInstanceState.getString(STATE_MESSAGE); } else { // Initialize with default values this.message = "Hello, World!"; } } This would also require the following two lines at the top of the class: private static final String STATE_MESSAGE = "MainActivityMessageState"; public String message; STATE_MESSAGE is a constant that defines the key to use when archiving the message instance variable in the bundle. This is similar to the key-value pattern for storing information in an Intent object. Saving Instance State To archive custom instance variables, all you need to do is override the onSaveInstanceState() method defined by Activity. For example, to save the above message state, you would use something like this:
  • 39. 39 @Override public void onSaveInstanceState(Bundle savedInstanceState) { savedInstanceState.putString(STATE_MESSAGE, this.message); super.onSaveInstanceState(savedInstanceState); } As with the Activity state transition methods, it’s important to call the superclass version of onSaveInstanceState() when overriding it. View States The Android framework will automatically save the state of the entire view hierarchy, which means that every text field, button, and image will look exactly as it did before it was destroyed by the system. For many activities, this is the only state that really needs to be saved—one of the few times you’ll actually need to implement a custom onSaveInstanceState() is when the Activity has multiple steps and the user’s progress is recorded in instance variables. Example Project The ActivityLifecycle-transitions project in the resource package for this book is a simple application demonstrating all of the transition methods discussed above. It has two activities that you can switch between, and both of them use Log.d() to inform you when they have changed states. When you run the project in the emulator and click the buttons, you should see the following messages in LogCat: 05-23 12:27:41.178: D/MainActivity(4042): Created Main Activity 05-23 12:27:41.178: D/MainActivity(4042): Started Main Activity 05-23 12:27:41.178: D/MainActivity(4042): Resumed Main Activity // Click the "Next Activity" button 05-23 12:27:44.788: D/MainActivity(4042): Paused Main Activity 05-23 12:27:45.018: D/SecondActivity(4042): Created Second Activity 05-23 12:27:45.018: D/SecondActivity(4042): Started Second Activity 05-23 12:27:45.018: D/SecondActivity(4042): Resumed Second Activity 05-23 12:27:45.728: D/MainActivity(4042): Stopped Main Activity Also notice that if you press the Power button on the emulator (which emulates the physical power button on an actual device), you’ll see the current activity pause and then stop. You can also see the current activity get destroyed when you press the emulator’s Back button. Of course, you’ll generally want to do more than just log a message in onCreate(), onStart(), and the other activity transition methods, but this project does give you a convenient place to start experimenting with the various states of an Activity. We’ll see some more practical versions of these methods later in the book after we learn how to create animations and save user data.
  • 40. 40 Summary In this chapter, we introduced the lifecycle on an Activity object. As the user navigates an application, each Activity object passes through a created, started, resumed, paused, stopped, and destroyed state, often cycling between the middle four states several times before being destroyed. Since these state transitions happen so frequently, and mobile devices have such scarce system resources, properly transitioning between these states is an essential component for a satisfying user experience. This chapter focused more on the conceptual aspects on the Activity lifecycle because the concrete implementation of transition methods like onResume() is so application-specific. What you should take away from this chapter is a high-level understanding of how the Android framework manages its Activity objects. Once you understand that, it’s easy to adapt these concepts to your real-world application requirements. In the next two chapters, we’ll shift gears a bit and focus on configuring the front end of an Android application. First, we’ll learn how to arrange UI elements into user-friendly layouts, then in the following chapter, we’ll explore the API for buttons, text fields, spinners, and the other common input controls.
  • 41. 41 Chapter 4 User Interface Layouts Laying out the UI elements in each Activity is one of the most important aspects of Android app development. It defines the appearance of an app, how you collect and display information to your users, and how they navigate between the various activities that compose your application. The first chapter in Android Programming Succinctly provided a brief introduction to XML layouts, but this chapter will take a much deeper look at Android’s built-in layout options. In this chapter, we’ll learn how to arrange UI elements in linear, relative, and grid layouts, the common navigation patterns recommended by Android maintainers, and we’ll even take a brief look at how to develop device-independent layouts that can seamlessly stretch and shrink to different dimensions. This chapter goes hand-in-hand with the upcoming chapter, in which we’ll learn about all of the individual UI elements. The running example for this chapter uses buttons and text fields to demonstrate different layout functionality, but remember that you can substitute any of the UI elements discussed in the next chapter to the same effect. Loading an Android Project You can follow along with the examples for this chapter from a fresh Android project, but if you want to see the end result, you can load the UserInterfaceLayouts project contained in the sample code for this book. To open an existing project, launch Eclipse (with the ADT plugin), and select Import in the File menu. This will open a dialog that looks like the following figure:
  • 42. 42 Figure 20: Opening a project in Eclipse Open the General folder and select Existing Projects into Workspace, then click Next. In the next dialog, click Browse..., find the resource folder that came with this book, and open the UserInterfaceLayouts folder. After clicking Finish, you should see the project in the Package Explorer. Loading Layouts In the first chapter, we let the template load the XML layout file for us, but it’s important to understand how this works under the hood. Fortunately, it’s also a relatively simple process. When you compile a project, Android automatically generates a View instance from each of your XML layout files. Like String resources, these are accessed via the special R class under the static layout variable. For example, if you wanted to access the View instance created from a file called activity_main.xml, you would use the following: R.layout.activity_main To display this View object in an Activity, all you have to do is call the setContentView() method. The onCreate() method of the blank Activity template always contains a call to setContentView() to load the associated view into the Activity:
  • 43. 43 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } Note that you can pass any View instance to setContentView(); using the generated R.layout.activity_main object is just a useful convention for working with XML-based layouts. If you need to replace an Activity’s content dynamically, it’s perfectly legal to call setContentView() outside of onCreate(). Basic View Attributes Before we start talking about Android’s built-in layout schemes, it’s important to understand how to set the size and position of UI elements within a particular layout. The next three sections show you how to define the dimensions, padding, and margin of a UI element using various XML properties. Size To set the width of a particular UI element, all you need to do is add an android:layout_width attribute to that element in the XML layout file. Likewise, the android:layout_height attribute defines the height of the element. The value for either of these parameters must be one of the following:  wrap_content – This constant makes the element as big as it needs to be to contain its content.  match_parent – This constant makes the element match the width and height of the parent element.  An explicit dimension – Explicit dimensions can be measured in pixels (px), density- independent pixels (dp), scaled pixels based on preferred font size (sp), inches (in), or millimeters (mm). For example, android:layout_width="120dp" will make the element 120 device-independent pixels wide.  A reference to a resource – Dimension resources let you abstract reusable values into a resource file, just like we saw with strings.xml in the first chapter of this book. Dimension resources can be accessed using the @dimen/resource_id syntax, where resource_id is the unique ID of the resource defined in dimens.xml. Let’s start by exploring wrap_content. Change activity_main.xml to the following and compile the project (we’ll discuss the LinearLayout element later in this chapter): <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"
  • 44. 44 android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity" > <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Click me!" /> </LinearLayout> You should see a single button at the top of the screen, and since we used wrap_content for both of the dimensions, it should be just big enough to fit the “Click me!” text (with some default padding). If you change the text, the button will expand or shrink to match. The following figure shows you the button you have created in the activity_main.xml. Figure 21: A Button element using the wrap_content constant for both dimensions If you change android:layout_width and android:layout_height to match_parent, the button will fill the entire screen, since that’s how big the parent LinearLayout is: <Button android:layout_width="match_parent" android:layout_height="match_parent" android:text="Click me!" /> When you run this, it should look something like the following:
  • 45. 45 Figure 22: A Button element using the match_parent constant for both dimensions If you need more control over the size of your UI elements, you can always manually define their width and height using explicit values, like so: <Button android:layout_width="200dp" android:layout_height="60dp" android:text="Click me!" /> This makes the button 200 device-independent pixels wide by 60 device-independent pixels high, as you can see in the following figure: Figure 23: A Button element with an explicit width and height
  • 46. 46 The last option is to add an explicit dimension to dimens.xml and reference that from activity_main.xml. This is very useful if you have many elements that need to share the same dimension. Dimension resource references look just like string resource references, except you use @dimen instead of @string: <Button android:layout_width="@dimen/button_width" android:layout_height="@dimen/button_height" android:text="Click me!" /> Of course, you’ll also have to add these resources to dimens.xml before you compile the project: <resources> <!-- Default screen margins, per the Android Design guidelines. --> <dimen name="activity_horizontal_margin">16dp</dimen> <dimen name="activity_vertical_margin">16dp</dimen> <dimen name="button_width">200dp</dimen> <dimen name="button_height">60dp</dimen> </resources> This will have the exact same effect as the previous snippet, but now it’s possible to reuse the button_width and button_height values in other layouts (or for other elements in the same layout). It’s also worth noting that you can mix-and-match different methods for the width and height values. For example, it’s perfectly legal to use 200dp for the width and wrap_content for the height. Padding Padding is the space between an element’s content and its border. It can be defined via any of the following attributes, all of which take an explicit dimension (e.g., 120dp) or a reference to a resource (e.g., @dimen/button_padding):  android:padding – Sets a uniform value for all sides of the element.  android:paddingTop – Sets the padding for the top edge of the element.  android:paddingBottom – Sets the padding for the bottom edge of the element.  android:paddingLeft – Sets the padding for the left edge of the element.  android:paddingRight – Sets the padding for the right edge of the element.  android:paddingStart – Sets the padding for the start edge of the element.  android:paddingEnd – Sets the padding for the end edge of the element.
  • 47. 47 Figure 24: Padding attributes Padding can be added to View or ViewGroup elements. For the former, it defines the space between the element’s contents (e.g., a button’s title text) and its border, and for the latter it defines the space between the edge of the group and all of its child elements. For example, the following button will have 60 device-independent pixels surrounding its title text: <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="60dp" android:text="Click me!" /> This should result in the following: Figure 25: A Button with 60dp padding Next, let’s try adding some padding to the top and bottom of the containing ViewGroup (i.e., the LinearLayout element) and making the button match the size of its parent, like so: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
  • 48. 48 android:layout_height="match_parent" android:orientation="vertical" android:paddingTop="24dp" android:paddingBottom="24dp" tools:context=".MainActivity" > <Button android:layout_width="match_parent" android:layout_height="match_parent" android:text="Click me!" /> </LinearLayout> This demonstrates that using match_parent on a child element takes the padding of the parent into account. Notice the 24dp padding on the top and bottom of the following screenshot: Figure 26: A Button with match_parent for its width and height and 24dp top and bottom padding in its parent ViewGroup Margin An element’s margin is the space between its border and either the surrounding elements or the edges of the parent element. It can be specified for any View or ViewGroup using the android:layout_margin element. And, like android:padding, the top, bottom, left, right, start, and end margins can be defined individually using android:layout_marginTop, android:layout_marginBottom, etc.
  • 49. 49 Figure 27: Margin attributes For instance, the following code creates the same result as the example from the previous section by defining a top and bottom margin on the Button instead of top and bottom padding on the parent LinearLayout: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity" > <Button android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginTop="24dp" android:layout_marginBottom="24dp" android:text="Click me!" /> </LinearLayout> Common Layouts Android provides three main ways to arrange UI elements: linear layouts, relative layouts, and grid layouts. The first two methods use classes called LinearLayout and RelativeLayout, respectively. These are subclasses of ViewGroup that have built-in functionality for setting the position and size of their child View objects. Grid layouts make it easy to display one- and two- dimensional data structures to the user, and they are slightly more complex than linear or relative layouts. The following figure shows you the available layout elements:
  • 50. 50 Figure 28: The three standard Android layouts Linear Layouts The LinearLayout class arranges all of the contained UI elements either horizontally or vertically. It displays each element in the same order it appears in the XML file, making it a very simple way to create complex layouts made up of many elements. Orientation A LinearLayout element needs to know in which direction it should lay out its children. This is specified via the android:orientation attribute, which can have a value of either horizontal or vertical. A horizontal layout will have each child element stacked left-to-right (in the same order as they appear in the source XML). For example, try changing activity_main.xml to the following: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" tools:context=".MainActivity" > <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Click me!" />
  • 51. 51 <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Click me!" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Click me!" /> </LinearLayout> If you compile the project and run it in the emulator, you should see a single row of three buttons, like the following: Figure 29: A LinearLayout with horizontal orientation But if you change the orientation to vertical, like so: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity" > ... </LinearLayout> The three buttons will appear in a single column:
  • 52. 52 Figure 30: A LinearLayout with vertical orientation Weight You can use the same android:layout_width and android:layout_height attributes discussed earlier this chapter to define the size of each child element, but LinearLayout also enables another sizing option called android:layout_weight. An element’s weight determines how much space it takes up relative to its siblings. For example, if you want three buttons to be evenly distributed over the height of the parent LinearLayout, you could use the following: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity" > <Button android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:text="Click me!" /> <Button android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:text="Click me!" /> <Button android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:text="Click me!" />
  • 53. 53 </LinearLayout> Note that for vertical orientations, you need to set each element’s android:layout_height attribute to 0 so that it can be calculated automatically using the specified weight. For horizontal orientations, you would need to set their android:layout_width to 0. Running the above code should give you the following: Figure 31: Evenly weighted UI elements in a vertical linear layout You can change the weight ratios to make the buttons take up different proportions of the screen. For example, changing the button weights to 2, 1, 1 will make the first button take up half the screen and the other two a fourth of the screen:
  • 54. 54 Figure 32: Unevenly weighted UI elements in a vertical linear layout Specifying weights instead of explicit dimensions for UI elements is a flexible way to configure layouts, as it lets them automatically scale to match the size of the parent ViewGroup. Relative Layouts RelativeLayout is an alternative to LinearLayout that lets you specify where each element should be placed with respect to the other elements in the interface. Unlike LinearLayout, the order of the elements in the rendered interface of a RelativeLayout does not necessarily have to match the underlying XML file. Instead, their positions are defined by specifying a relationship to another element (e.g., “place the button to the left of the text field” or “place the button at the bottom of its parent”). The fact that positions are defined relative to other elements makes this a very powerful way to create pleasing UIs that expand and contract based on the screen size. Relative To Parent In a RelativeLayout, a UI element can be positioned with respect to its parent or with respect to its siblings. In either case, you define the position using one of the layout attributes defined by RelativeLayouts.LayoutParams. The attributes that position elements relative to their parent are listed below, and all of them take a Boolean value:  android:layout_alignParentLeft – If true, aligns the left side of the element with the left side of its parent.  android:layout_centerHorizontal – If true, centers the element horizontally in its parent.
  • 55. 55  android:layout_alignParentRight – If true, aligns the right side of the element with the right side of its parent.  android:layout_alignParentTop – If true, aligns the top of the element to the top of its parent.  android:layout_centerVertical – If true, centers the element vertically in its parent.  android:layout_alignParentBottom – If true, aligns the bottom of the element to the bottom of its parent.  android:layout_alignParentStart – If true, aligns the start edge of the element with the start edge of its parent.  android:layout_alignParentEnd – If true, aligns the end edge of the element with the end edge of its parent.  android:layout_centerInParent – If true, centers the element horizontally and vertically in its parent. For example, try changing activity_main.xml to the following: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" > <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_alignParentBottom="true" android:text="Top Button" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:text="Middle Button" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:text="Bottom Button" /> </RelativeLayout> This will result in a diagonal row of three buttons, as shown below:
  • 56. 56 Figure 33: A RelativeLayout that positions elements with respect to their parent Note that if you change the order of the XML elements in activity_main.xml, the buttons will still appear in the same locations. This is different than the behavior of LinearLayout, which places each element relative to the previous one. Also notice that if you change the button dimensions or rotate the emulator (Ctrl+F12), they will still appear in their respective locations relative to the screen. Relative To Siblings Elements can also be positioned relative to each other. The attributes listed below all specify a graphical relationship with surrounding elements, but instead of a Boolean value, they require an ID of another element in the layout:  android:layout_above – Positions the bottom edge of the element above the element with the specified ID.  android:layout_below – Positions the top edge of the element below the element with the specified ID.  android:layout_toLeftOf – Positions the right edge of the element to the left of the element with the specified ID.  android:layout_toRightOf – Positions the left edge of the element to the right of the element with the specified ID.  android:layout_alignBaseline – Aligns the baseline of the element with the baseline of the element with the specified ID.  android:layout_alignTop– Aligns the top edge of the element with the top of the element with the specified ID.
  • 57. 57  android:layout_alignBottom – Aligns the bottom edge of the element with the bottom edge of the element with the specified ID.  android:layout_alignLeft – Aligns the left edge of the element with the left edge of the element with the specified ID.  android:layout_alignRight – Aligns the right edge of the element with the right edge of the element with the specified ID. For example, consider the following RelativeLayout that uses relative-to-sibling attributes instead of relative-to-parent attributes. The second and third buttons are positioned relative to the first one, which will be located in the default top-left corner. <Button android:id="@+id/topButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Top Button" /> <Button android:id="@+id/middleButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/topButton" android:layout_toRightOf="@id/topButton" android:text="Middle Button" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/middleButton" android:layout_toRightOf="@id/middleButton" android:text="Bottom Button" /> Instead of a diagonal line of buttons that spans the entire screen, this code will give you a diagonal with all of the button corners touching: Figure 34: A RelativeLayout that positions elements with respect to their siblings
  • 58. 58 Since we’re referencing them by ID, we needed to include an android:id attribute for the top and middle buttons. Remember from the first chapter that the first time an XML element ID is used, it needs to be declared as "@+id/foo". This plus sign usually occurs in the android:id attribute, but it doesn’t have to—it should always be found in the first attribute that uses the ID. In the following snippet, the android:layout_toLeftOf attributes are the first place the middleButton and bottomButton IDs are referenced, so they need to be prefixed by a plus sign: <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toLeftOf="@+id/middleButton" android:layout_above="@id/middleButton" android:text="Top Button" /> <Button android:id="@id/middleButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toLeftOf="@+id/bottomButton" android:layout_above="@id/bottomButton" android:text="Middle Button" /> <Button android:id="@id/bottomButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_alignParentBottom="true" android:text="Bottom Button" /> This use of plus signs helps reduce the number of mistyped IDs by ensuring that new IDs are explicitly labeled as such. For example, if you were to accidentally try to reference an element with @id/bottumButton, the compiler would let you know that there is no such element. The above XML positions the top and middle buttons relative to the bottom one, then puts the bottom one in the bottom-right corner of the screen. This gives you the following layout:
  • 59. 59 Figure 35: A RelativeLayout that positions buttons relative to elements that have not been declared yet Also notice that you can combine the relative-to-sibling with the relative-to-parent positioning methods. The bottom button is positioned relative to its parent (e.g., android:layout_alignParentRight), and the others are positioned relative to a sibling (e.g., android:layout_toLeftOf). List and Grid Layouts So far, we’ve learned how to quickly create user interfaces with LinearLayout and RelativeLayout; however, the content of these interfaces have been entirely static—their UI elements are hardcoded into the underlying XML file. When you want to create a user interface using dynamic data, things get a little bit more complicated. Data-driven layouts require three components:  A data set  A subclass of Adapter for converting the data items into View objects.  A subclass of AdapterView for laying out the View objects created by the Adapter Before you can start configuring a data-driven layout, you need some data to work with. For this section, our data set will be a simple array of String objects, but Android also provides many built-in classes for fetching data from text files, databases, or web services. Next, you need an Adapter to convert the data into View objects. For example, the built-in ArrayAdapter takes an array of objects, creates a TextView for each one, and sets its text property to the toString() value of each object in the array. These TextView instances are then sent to an AdapterView.
  • 60. 60 AdapterView is a ViewGroup subclass that replaces the LinearLayout and RelativeLayout classes from the previous sections. Its job is to arrange the View objects provided by the Adapter. This section explores the two most common AdapterView subclasses, ListView and GridView, which position these views into a list or a grid, respectively. Figure 36: Displaying a data set in a GridView using an Adapter List Layouts Let’s start by getting a simple ListView up and running. Since we’re no longer hardcoding UI elements, our XML layout file is going to be very simple—all it needs is an empty ListView element. Change activity_main.xml to the following: <ListView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/listView" android:layout_width="wrap_content" android:layout_height="wrap_content" /> This ListView defines our entire XML layout—all of its UI elements will be populated dynamically. We do, however, need to include an android:id attribute so that we can access the ListView instance from our activity. Next, we need to update our MainActivity class to define a data set, pass that data set to an Adapter, and then pass that adapter to the ListView that we defined in activity_main.xml. So, change MainActivity.java to the following: package com.example.userinterfacelayouts; import android.os.Bundle; import android.app.Activity; import android.widget.ListView; import android.widget.ArrayAdapter; public class MainActivity extends Activity { @Override
  • 61. 61 protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); String[] data = new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }; ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, data); ListView listView = (ListView) findViewById(R.id.listView); listView.setAdapter(adapter); } } First, we create an array of Strings to serve as our data set and assign it to the local data variable. Then, we create an ArrayAdapter, which generates a TextView from each String in the array. Its constructor takes an Activity context, the ID of the prototypical TextView, and the array of data. The android.R.layout.simple_list_item_1 snippet is a reference to one of Android’s convenient built-in layouts. You can find the complete list in the R.layout documentation. Next, we have to find the ListView that we added to activity_main.xml via findViewById(), and then we need to set its adapter property to the ArrayAdapter instance that we just configured. You should now be able to compile the project and see the four strings in the data array displayed as a list of TextView elements: Figure 37: A dynamic layout generated by ListView List layouts make it incredibly easy to work with large data sets, and the fact that you can represent each item with any view lets you display objects that have several properties (e.g., a list of contacts that all display an image, name, and preferred phone number).
  • 62. 62 Grid Layouts Grid layouts use the same data/Adapter/AdapterView pattern as list layouts, but instead of ListView, you use the GridView class. GridView also defines some extra configuration options for defining the number of columns and the spacing between each grid item, most of which are included in the following snippet. Try changing activity_main.xml to: <GridView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/gridView" android:layout_width="fill_parent" android:layout_height="fill_parent" android:columnWidth="100dp" android:numColumns="auto_fit" android:verticalSpacing="5dp" android:horizontalSpacing="5dp" android:stretchMode="columnWidth" /> The only change we need to make in MainActivity.java is to update the ListView references to GridView: package com.example.userinterfacelayouts; import android.os.Bundle; import android.app.Activity; import android.widget.GridView; import android.widget.ArrayAdapter; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); String[] data = new String[] { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5", "Item 6", "Item 7", "Item 8", "Item 9"}; ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, data); GridView gridView = (GridView) findViewById(R.id.gridView); gridView.setAdapter(adapter); } } This will give you a nice grid of text fields that are 100 device-independent pixels wide with 5 device-independent pixels between each one:
  • 63. 63 Figure 38: A dynamic layout generated by GridView Handling Click Events Of course, you’re probably going to want to allow the user to interact with the items in a ListView or a GridView. However, because the interface generated by either of these classes is dynamic, we can’t use the android:onClick XML attribute to call a method when the user clicks one of the list items. Instead, we have to define a general callback function in MainActivity.java. This can be accomplished by implementing the AdapterView.OnItemClickListener interface, like so: package com.example.userinterfacelayouts; import android.os.Bundle; import android.app.Activity; import android.widget.GridView; import android.widget.ArrayAdapter; import android.util.Log; import android.view.View; import android.widget.TextView; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; public class MainActivity extends Activity { private static final String TAG = "MainActivity"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
  • 64. 64 String[] data = new String[] { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5", "Item 6", "Item 7", "Item 8", "Item 9"}; ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, data); GridView gridView = (GridView) findViewById(R.id.gridView); gridView.setAdapter(adapter); gridView.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView<?> parent, View v, int position, long id) { TextView selectedView = (TextView) v; Log.d(TAG, String.format("You clicked: %s", selectedView.getText())); } }); } } Now, the onItemClick() method will be called every time one of the GridView’s items are clicked. All of the relevant parameters are passed to this function as parameters: the parent AdapterView, the View item that was clicked, its position in the data set, and its row id. The above callback simply casts the clicked View to a TextView and displays whatever text it contains in LogCat. Clicks can be handled in the exact same way for ListView layouts. Editing The Data Set When you want to change the data that is displayed to the user at runtime, all you have to do is edit the underlying data set and the built-in BaseAdapter class takes care of updating the user interface accordingly. In this section, we’ll add a button to the layout so the user can add new items to the grid, and then we’ll re-implement the onItemClick() function to remove the selected item from the list. First, let’s change activity_main.xml to include a button. We’ll do this by making LinearLayout the root XML element and giving it a Button and a GridView for children: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" tools:context=".MainActivity" > <Button android:layout_width="match_parent" android:layout_height="80dp" android:text="Add Item" android:onClick="addItem"/> <GridView android:id="@+id/gridView"
  • 65. 65 android:layout_width="fill_parent" android:layout_height="fill_parent" android:columnWidth="100dp" android:numColumns="auto_fit" android:verticalSpacing="5dp" android:horizontalSpacing="5dp" android:stretchMode="columnWidth" /> </LinearLayout> Notice that it’s perfectly legal to nest different layout schemes inside of each other (i.e., putting a GridView inside of a LinearLayout). This makes it possible to create complex, dynamic user interfaces with very little effort. Next, we need to alter the corresponding activity to handle Add Item button clicks and remove items when they are selected in the GridView. This will require a number of changes to MainActivity.java: package com.example.userinterfacelayouts; import android.os.Bundle; import android.app.Activity; import android.widget.GridView; import android.widget.ArrayAdapter; import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import java.util.ArrayList; public class MainActivity extends Activity { private ArrayList<String> data; private ArrayAdapter<String> adapter; private int count; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); this.data = new ArrayList<String>(); this.data.add("Item 1"); this.data.add("Item 2"); this.data.add("Item 3"); this.count = 3; adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, data); GridView gridView = (GridView) findViewById(R.id.gridView); gridView.setAdapter(adapter); gridView.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
  • 66. 66 data.remove(position); adapter.notifyDataSetChanged(); } }); } public void addItem(View view) { count++; String newItem = String.format("Item %d", count); this.data.add(newItem); this.adapter.notifyDataSetChanged(); } } First, we have to change the static String[] array that represents our data set to a mutable ArrayList. This will allow us to add and remove items. We also have to change the data and adapter local variables to instance variables so that we can access them outside of onCreate(). We also added a count variable to keep track of how many items have been created. To remove an item from the the GridView, all we have to do is remove it from the data set with ArrayList’s remove() method, then call adapter.notifyDataSetChanged(). This latter method is defined by BaseAdapter, and it tells the Adapter that it needs to synchronize its associated AdapterView items. It should be called whenever the underlying data set has changed. The new addItem() method is called whenever the Add Item button is clicked. First it increments the count variable, then uses it to generate a title for the new item, adds the title to the data set, and finally calls notifyDataSetChanged() to refresh the GridView. Figure 39: Adding and removing items from the data set