Creating Android Applications


Chris Haseman Creating Android Applications DEVELOP AND DESIGN Creating Android Applications DEVELOP AND DESIGN Chris Haseman Creating Android Applications: Develop and Design Chris Haseman Peachpit Press 1249 Eighth Street Berkeley, CA 94710 510/524-2178 510/524-2221 (fax) Find us on the Web at: www.peachpit.com To report errors, please send a note to errata@peachpit.com Peachpit Press is a division of Pearson Education. Copyright © 2012 by Chris Haseman Editor: Clifford Colby Development editor: Robyn Thomas Production editor: Myrna Vladic Copyeditor: Scout Festa Technical editor: Jason LeBrun Cover design: Aren Howell Straiger Interior design: Mimi Heft Compositor: Danielle Foster Indexer: Valerie Haynes Perry Notice of Rights All rights reserved. No part of this book may be reproduced or transmitted in any form by any means, electronic, mechanical, photocopying, recording, or otherwise, without the prior written permission of the publisher. For information on getting permission for reprints and excerpts, contact permissions@peachpit.com. Notice of Liability The information in this book is distributed on an “As Is” basis without warranty. While every precaution has been taken in the preparation of the book, neither the author nor Peachpit shall have any liability to any person or entity with respect to any loss or damage caused or alleged to be caused directly or indirectly by the instructions contained in this book or by the computer software and hardware products described in it. Trademarks Android is a trademark of Google Inc., registered in the United States and other countries. Many of the designations used by manufacturers and sellers to distinguish their products are claimed as trademarks. Where those designations appear in this book, and Peachpit was aware of a trademark claim, the designa- tions appear as requested by the owner of the trademark. All other product names and services identified throughout this book are used in editorial fashion only and for the benefit of such companies with no intention of infringement of the trademark. No such use, or the use of any trade name, is intended to convey endorsement or other affiliation with this book. ISBN-13: 978-0-321-78409-4 ISBN-10: 0-321-78409-x 9 8 7 6 5 4 3 2 1 Printed and bound in the United States of America To my wife, Meghan, who’s made me the teacher, writer, and man I am today. BIO Chris Haseman has been writing mobile software in various forms since 2003. He was involved in several large-scale BREW projects, from MMS messaging to Major League Baseball. More recently, he was an early Android engineer behind the doubleTwist media player, and he is now the lead Android developer for the website Tumblr. He’s a faculty member of General Assembly in NYC, where he teaches Android development. He lives in Brooklyn, where he constantly debates shaving his beard. IV CREATING ANDROID APPLICATIONS: DEVELOP AND DESIGN As always, I could spend more pages thanking people than are in the work itself. Here are a few who stand out: David and Susanne H for their support. Ellen Y. for believing so early that I could do this. JBL for fixing my code. Robyn T. for her patience. Cliff C. for finding me. Scout F. for her tolerance of my grammar. Sharon H. for her harassment IMs. Dan C. for his backing. Edwin and Susan K. for their care. Thomas K. for his subtle and quiet voice. Sparks for his humor. Cotton for “being there.” Lee for the place to write. The teams at both Tumblr and doubleTwist for all their encouragement. The Android team at Google for all their hard work. Most of all, Peachpit for giving me the opportunity to write for you. ACKNOWLEDGMENTS ACKNOWLEDGMENTS V CONTENTS Introduction ...........................................................xi Welcome to Android ................................................ xiii CHAPTER 1 GETTING STARTED WITH ANDROID ........................... 2 Downloading Developer Software .................................... 4 The Android Software Development Kit ............................... 4 Eclipse ................................................................... 4 Java ..................................................................... 4 Getting Everything Installed .......................................... 5 Installing Eclipse ....................................................... 5 Installing the Android SDK ............................................. 5 Downloading a Package ................................................ 6 Configuring Eclipse ................................................... 8 Adding the Android Plug-in to Eclipse ................................. 8 Locating the SDK ....................................................... 9 Creating an Emulator ................................................. 10 Working with Your Android Phone .................................... 12 Creating a New Android Project ..................................... 14 Running a New Project ................................................ 17 Troubleshooting the Emulator ...................................... 18 Wrapping Up ......................................................... 19 CHAPTER 2 EXPLORING THE APPLICATION BASICS ....................... 20 The Files .............................................................. 22 The Manifest ........................................................... 22 The Activity Class .................................................... 23 Watching the Activity in Action ....................................... 23 Implementing Your Own Activity ..................................... 24 The Life and Times of an Activity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 Bonus Round—Data Retention Methods .............................. 35 The Intent Class ...................................................... 37 Manifest Registration .................................................. 37 Adding an Intent ...................................................... 38 Listening for Intents at Runtime ...................................... 41 Moving Your Own Data ................................................ 45 The Application Class ................................................ 48 The Default Application Declaration ................................. 48 VI CREATING ANDROID APPLICATIONS: DEVELOP AND DESIGN Customizing Your Own Application ................................... 48 Accessing the Application ............................................. 50 Wrapping Up ......................................................... 51 CHAPTER 3 CREATING USER INTERFACES ................................. 52 The View Class ....................................................... 54 Creating a View ........................................................ 54 Altering the UI at Runtime ............................................ 58 Handling a Few Common Tasks ....................................... 61 Creating Custom Views ................................................ 65 Resource Management ............................................... 71 Resource Folder Overview ............................................. 71 Values Folder .......................................................... 73 Layout Folders . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 Drawable Folders . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 Layout Management ................................................. 77 The ViewGroup ........................................................ 77 The AbsoluteLayout ................................................... 78 The LinearLayout ...................................................... 82 The RelativeLayout ................................................... 90 Wrapping Up ......................................................... 97 CHAPTER 4 ACQUIRING DATA ............................................ 98 The Main Thread .................................................... 100 You There, Fetch Me that Data! ..................................... 100 Watchdogs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101 What Not to Do . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102 When Am I on the Main Thread? ................................... 102 Getting Off the Main Thread ........................................ 103 Getting Back to Main Land .......................................... 104 There Must Be a Better Way! ......................................... 105 The AsyncTask ...................................................... 106 How to Make It Work for You ....................................... 108 A Few Important Caveats ............................................ 111 The IntentService ................................................... 113 Declaring a Service ................................................... 113 Fetching Images ...................................................... 114 CONTENTS VII Checking Your Work ................................................. 120 Wrapping Up ........................................................ 122 CHAPTER 5 ADAPTERS, LISTVIEWS, AND LISTS .......................... 124 Two Pieces to Each List ............................................. 126 ListView ............................................................... 126 Adapter ............................................................... 126 A Main Menu ........................................................ 127 Creating the Menu Data .............................................. 127 Creating a ListActivity ................................................ 128 Defining a Layout for Your ListActivity .............................. 128 Making a Menu List Item ............................................. 130 Creating and Populating the ArrayAdapter . . . . . . . . . . . . . . . . . . . . . . . . . 131 Reacting to Click Events .............................................. 133 Complex List Views ................................................. 134 The 1000-foot View ................................................... 134 Creating the Main Layout View ...................................... 134 Creating the ListActivity ............................................. 135 Getting Twitter Data ................................................. 136 Making a Custom Adapter ........................................... 138 Building the ListViews ................................................ 141 How Do These Objects Interact? ................................... 144 Wrapping Up ........................................................ 145 CHAPTER 6 THE WAY OF THE SERVICE ................................... 146 What Is a Service? .................................................. 148 The Service Lifecycle .................................................. 148 Keeping Your Service Running ....................................... 149 Shut It Down! ......................................................... 149 Communication ..................................................... 150 Intent-Based Communication ........................................ 150 Binder Service Communication ..................................... 160 Wrapping Up ........................................................ 166 CHAPTER 7 MANY DEVICES, ONE APPLICATION ......................... 168 Uncovering the Secrets of the res/ Folder .......................... 170 Layout Folders . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170 What Can You Do Beyond Landscape? ............................... 177 VIII CREATING ANDROID APPLICATIONS: DEVELOP AND DESIGN The Full Screen Define ................................................ 177 Limiting Access to Your App to Devices That Work ................ 180 The Tag ...................................................... 180 SDK Version Number ................................................. 181 Handling Code in Older Android Versions ......................... 182 SharedPreferences and Apply ........................................ 182 Reflecting Your Troubles Away ....................................... 183 Always Keep an Eye on API Levels .................................... 184 Wrapping Up ........................................................ 185 CHAPTER 8 MOVIES AND MUSIC ........................................ 186 Movies ............................................................... 188 Adding a VideoView .................................................. 188 Setting up for the VideoView ......................................... 189 Getting Media to Play ............................................... 190 Loading and Playing Media . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192 Cleanup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193 The Rest, as They Say, Is Up to You ................................... 194 Music ................................................................ 195 MediaPlayer and State ............................................... 195 Playing a Sound ...................................................... 196 Cleanup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197 It really is that simple ................................................ 197 Longer-Running Music Playback ................................... 198 Binding to the Music Service ......................................... 198 Finding the Most Recent Track ....................................... 199 Playing the Audio in the Service .................................... 201 Cleanup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204 Interruptions ........................................................ 205 Wrapping Up ........................................................ 207 CHAPTER 9 DETERMINING LOCATIONS AND USING MAPS .............. 208 Location Basics ...................................................... 210 Mother May I? ........................................................ 210 Be Careful What You Ask For ......................................... 210 Finding a Good Supplier .............................................. 211 Getting the Goods ..................................................... 211 CONTENTS IX The Sneaky Shortcut ................................................. 213 That’s It! .............................................................. 213 Show Me the Map! .................................................. 214 Getting the Library ................................................... 214 Adding to the Manifest ............................................... 214 Creating the MapActivity ............................................ 215 Creating a MapView .................................................. 216 Run, Baby, Run ........................................................ 217 Wrapping Up ........................................................ 219 CHAPTER 10 TABLETS, FRAGMENTS, AND ACTION BARS, OH MY ......... 220 Fragments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222 The Lifecycle of the Fragment ....................................... 222 Creating a Fragment ................................................ 224 Showing a Fragment ................................................ 225 Providing Backward Compatibility ................................. 230 The Action Bar ...................................................... 232 Showing the Action Bar .............................................. 232 Adding Elements to the Action Bar .................................. 233 Wrapping Up ........................................................ 237 CHAPTER 11 PUBLISHING YOUR APPLICATION ........................... 238 Packaging and Versioning ........................................... 240 Preventing Debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 240 Naming the Package ................................................. 240 Versioning ............................................................ 241 Setting a Minimum SDK value ...................................... 242 Packaging and Signing .............................................. 243 Exporting a Signed Build . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243 Backing Up Your Keystore File ....................................... 244 Submitting Your Build .............................................. 246 Watch Your Crash Reports and Fix Them ........................... 246 Update Frequently ................................................... 246 Wrapping Up ........................................................ 247 Index.................................................................248 X CREATING ANDROID APPLICATIONS: DEVELOP AND DESIGN INTRODUCTION If you’ve got a burning idea for an application that you’re dying to share, or if you recognize the power and possibilities of the Android platform, you’ve come to the right place. This is a short book on an immense topic. I don’t mean to alarm anyone right off the bat here, but let me be honest: Android development is hard. Its architecture is dissimilar to that of many existing platforms (especially other mobile SDKs), there are many traps for beginners to fall into, and the documentation is frequently sparse at best. In exchange for its difficulty, however, Google’s Android offers unprecedented power, control, and—yes—responsibility to those who are brave enough to develop for it. This is where my job comes in. I’m here to make the process of learning to write amazing Android software as simple as possible. Who am I to ask such things of you? I’ve been writing mobile software in a professional capacity for more than eight years, and for three of those years, I’ve been developing software for Android. I’ve written code that runs on millions of handsets throughout the world. Also, I have a beard. We all know that people with ample facial hair appear to be more authoritative on all subjects. In return for making this learning process as easy as possible, I ask for a few things: ᭿ You have a computer. My third-grade teacher taught me never to take any- thing for granted; maybe you don’t have a computer. If you don’t already have a computer, you’ll need one—preferably a fast one, because the Android emulator and Eclipse can use up a fair amount of resources quickly. ᭿ You’re fluent in Java. Notice that I say fluent, not expert. Because you’ll be writing usable applications (rather than production libraries, at least to start), I expect you to know the differences between classes and interfaces. You should be able to handle threads and concurrency without batting an eyelash. Further, the more you know about what happens under the hood (in terms of object creation and garbage collection), the faster and better your mobile applications will be. Yes, you can get through the book and even put together rudimentary applications without knowing much about the Java programming language. NOTE: Android is an equal opportunity development platform. While I personally develop on a Mac, you can use any of the three major platforms (Mac, PC, or Linux). INTRODUCTION XI However, when you encounter problems—in both performance and pos- sibilities—a weak foundation in the programming language may leave you without a solution. ᭿ You have boundless patience and endless curiosity. Your interest in and passion for Android will help you through the difficult subjects covered in this book and let you glide through the easy ones. Throughout this book, I focus on how to write features, debug problems, and make interesting software. I hope that when you’ve finished the book, you’ll have a firm grasp of the fundamentals of Android software development. All right, that’s quite enough idle talking. Let’s get started. WHO THIS BOOK IS FOR This book is for people who have some programming experience and are curious about the wild world of Android development. WHO THIS BOOK IS NOT FOR This book is not for people who have never seen a line of Java before. It is also not for expert Android engineers with several applications under their belt. HOW YOU WILL LEARN In this book, you’ll learn by doing. Each chapter comes with companion sample code and clear, concise instructions for how to build that code for yourself. You’ll find the code samples on the book’s website (www.peachpit.com/androiddevelopanddesign). WHAT YOU WILL LEARN You’ll learn the basics of Android development, from creating a project to building scalable UIs that move between tablets and phones. NOTE: If you’re more interested in the many “whys” behind Android, this book is a good one to start with, but it won’t answer every question you may have. XII CREATING ANDROID APPLICATIONS: DEVELOP AND DESIGN i WELCOME TO ANDROID WELCOME TO ANDROID Eclipse and the Android SDK are the two major tools you’ll use to follow along with the examples in this book. There are, however, a few others you should be aware of that will be very useful now and in your future work with Android. While you may not use all of these tools until you’re getting ready to ship an application, it will be helpful to know about them when the need arises. THE TOOLS Over the course of this book, you’ll work with several tools that will make your life with Google’s Android much easier. Here they are in no particular order: ECLIPSE Eclipse is the primary tool that I’ll be using throughout the book. Google has blessed it as the primary IDE for Android development and has released plug-ins to help. Make sure you get them, because they take all the pain out of creat- ing a project and stepping through your application on the device. You’re welcome to use Eclipse as well, or, if you’re some sort of command-line junkie, you can follow along with Vim or Emacs if you prefer. ANDROID SDK The Android SDK contains all the tools you’ll need to develop Android applica- tions from the command line as well as other tools to help you find and diagnose problems and streamline your applica- tions. You can download the Android SDK at http://developer.android .com/sdk/index.html. XIV CREATING ANDROID APPLICATIONS: DEVELOP AND DESIGN ANDROID SDK MANAGER The Android SDK Manager (found within the SDK tools/ directory) will help you pull down all versions of the SDK as well as a plethora of tools, third-party add-ons, and all things Android. This will be the primary way in which you get new software from Google’s headquarters in Moun- tain View, California. HIERARCHY VIEWER This tool will help you track the complex con- nections between your layouts and views as you build and debug your applications. This viewer can be indispensable when tracking down those hard-to-understand layout issues. You can find this tool in the SDK tools/ directory as hierarchyviewer. DDMS DDMS (Dalvik Debug Monitor Server) is your primary way to interface with and debug Android devices. You’ll find it in the tools/ directory inside the Android SDK. It does everything from gathering logs, sending mock text messages or locations, and mapping memory allocations to taking screenshots. Eclipse users have a perspective that duplicates, within Eclipse, all the functionality that this stand-alone applica- tion offers. This tool is very much the Swiss Army knife of your Android toolkit. WELCOME TO ANDROID XV 1 GETTING STARTED WITH ANDROID The first step when building an Android appli- cation is installing the tools and the SDK. If you’ve already built an Android application, congratulations are in order! You can skip this chapter and move on to the fundamentals. For those of you who haven’t, you’ll get through this busy work before you can say “Open Handset Alliance” three times quickly. In this chapter, you’ll move quickly through the platform con- figuration. I’ll show you how to download developer files from Google and the Eclipse project; install and configure the Android Software Development Kit (SDK) and Eclipse; create and configure a shiny new Android emulator; start a new Android project; and run your Android project on your shiny new Android emulator. 3 ng ls and the SDK. If you’ve already ion, congratulations are in order! g an Android applllliiiiii-- and the SDK. If you’ve already First, you need to download a few software tools—namely, the Android SDK, the Eclipse integrated development environment (IDE), and the Android plug-in for Eclipse. There are many other tools a developer could use to make Android applications, but I’ve found that this setup has the fewest hassles and will get you up and running in the least amount of time. THE ANDROID SOFTWARE DEVELOPMENT KIT Head over to the Android Developers website at http://developer.android.com. You’ll become intimately familiar with these pages as you work on this platform. Once on the site, find the section labeled SDK and download the offered files with reckless abandon. On Windows, it’s best if you use the offered installer. For you Mac and Linux users, you’ll get a zip file. Set the appropriate files to downloading and move on while they finish. ECLIPSE For versions of Eclipse newer than 3.5, Google recommends that you get the classic version of the IDE. Tap your way to www.eclipse.org/downloads and locate Eclipse Classic. (This chapter has screenshots from 3.6.1; the latest is, however, 3.7.1.) Make sure you get the right version for your system: 32-bit or 64-bit. Now get your twid- dling thumbs ready and wait for the installer to come through. Assuming that you’re not connecting through a telephone line that makes hissing noises, you should be finished in just a few minutes. In the meantime, I’ll entertain you with an opera about the nature of kittens . . . wait no, no I won’t. You’re welcome to browse ahead in the book while you down- load the required files. JAVA You’ll need to download and install Java on your system (depending on how much development you’ve done before, you might already have it installed). I assume you were already comfortable with Java before diving into this book; I’m also going to assume you’re comfortable installing the JDK yourself. DOWNLOADING DEVELOPER SOFTWARE 4 CHAPTER 1 GETTING STARTED WITH ANDROID GETTING EVERYTHING INSTALLED At this point, the process becomes a little more complicated and the herd of cats start to wander in different directions. Depending on which platform you’re run- ning, you may have to skip ahead from time to time. If the title doesn’t look like it applies to your operating system (OS), skip ahead until you find one that does. Bear with me; you’ll be working on your first application in no time. INSTALLING ECLIPSE Installing Eclipse, for the most part, is as simple as decompressing the file you’ve downloaded and putting the application somewhere you’ll remember. I recommend not launching Eclipse just yet. Wait until you’ve got the Android SDK squared away (see the next section). You may want to make sure that you’ve got the latest development tools in place. INSTALLING THE ANDROID SDK With Eclipse now in place, you’re just a few steps away from running your own Android application. Find the section that applies to your operating system, and follow the steps therein. INSTALLING THE SDK FOR MAC USERS To install the SDK, simply unzip the compressed file you downloaded from the Android Developers site (developer.android.com). Although you can unpack this file anywhere, I recommend placing it in /Users/yourUserName/Documents/ android_sdk/. If you are a command-line person, you should put two directories on your path as follows: 1. Navigate to /User/yourUserName/.profile. NOTE: For the duration of this book, I’m going to assume you’ll be using the Eclipse IDE for the majority of your development. I’ll try to include command-line methods as well as Eclipse screenshots for all important commands and tasks in case you’re rocking the terminal with Vim or Emacs. GETTING EVERYTHING INSTALLED 5 2. Assuming that you installed the SDK in the location I recommended, add the following code all on one line: export PATH=”$PATH”/Users/*yourUserName*/Documents/android_ sdk/tools”/Users/*yourUserName*/Documents/android_sdk/ platform-tools” Now, when you open a new terminal, typing which android will return the path where you installed your shiny new Android SDK. Keep this command in mind—you’ll return to it in a minute. INSTALLING THE SDK FOR LINUX USERS Linux users should go through nearly the same steps as in “Installing the SDK for Mac Users.” The only differences are the instructions for putting the SDK on your path and where you may want to put your version of the SDK. I’m going to assume that if you’re a Linux user, you’re savvy enough to figure out this procedure on your own. INSTALLING THE SDK FOR WINDOWS USERS To install the Android SDK for Windows, follow these steps: 1. Start the Android SDK installer. 2. Accept the installer’s default location and Start-menu configuration. 3. Let the installer work its magic. This procedure will add an SDK Manager command to your Start menu. This is the application you’ll work with to select the correct platforms in the next section. DOWNLOADING A PACKAGE All right, you’ve got the SDK downloaded and in the right place. You’re not quite there yet. 1. If you are a Mac or Linux user, run sdk location/tools/android; if you are a Windows user, allow the installer to open the AVD (Android Virtual Device) Manager software. You should see the Android SDK Manager. 6 CHAPTER 1 GETTING STARTED WITH ANDROID 2. Select Available Packages from the options in the left panel. 3. Select as many versions of the SDK as you like from the panel on the right. (At press time, there are still a few phones running 1.6.) At the very least, you’ll probably want Gingerbread (2.3.3), which many phones are running. You’ll need Honeycomb (for tablets) and Ice Cream Sandwich (the latest and greatest) for the last chapter of the book. If you’re in a rush, just grab 2.3.3 for now (Figure 1.1). 4. In the resulting dialog, click Install x Packages, agree to Google’s terms (read at your own risk), and away you go. The Android SDK Manager should download and install the two required platforms for you. So far, so good. Keep in mind that the platform you’re downloading corresponds to a particular version of the Android OS running on devices. Older phones may not support all the SDK calls that the latest phones might. As you learn about various SDK calls, I’ll show you strategies for dealing with older devices. FIGURE 1.1 Use the Android SDK Manager to select as many versions as you would like to install. NOTE: If you’ve closed it, you can find the SDK Manager program in your Start menu under Android SDK Tools. GETTING EVERYTHING INSTALLED 7 CONFIGURING ECLIPSE Fortunately, configuring Eclipse is consistent for Windows, Mac, and Linux. Fire up Eclipse and specify where you want to locate your workspace. It can, theoretically, be installed anywhere, but I always locate mine under ~/Documents/workspace on my Mac. As long as you consistently use the same directory, you shouldn’t encounter any problems. ADDING THE ANDROID PLUG-IN TO ECLIPSE Now that you’ve got Eclipse up and running, you’ll need to add Android’s ADT plug- in. This is the magic piece that will change Eclipse from a straight Java developer tool into a tool for making Android applications. 1. From the Eclipse Help menu, select Install New Software (Figure 1.2). 2. Enter https://dl-ssl.google.com/android/eclipse/ in the Work With field in the Install pop-up. Your settings should look like those in Figure 1.3. FIGURE 1.2 Where Eclipse has cleverly hidden the plug-in install wizard. FIGURE 1.3 The plug-in install wizard in all its dull glory. 8 CHAPTER 1 GETTING STARTED WITH ANDROID 3. Give the site a name of your choosing. Mine was simply “android_stuff.” You’ll be presented with the option to install a few packages. 4. Select them all and click Next, then click Next again. 5. Accept Google’s terms and conditions. Eclipse will download the appropri- ate plug-in packages. Before the download finishes, you might be warned that unsigned code is about to be installed. This is to be expected. (Don’t freak out.) 6. Accept the unsigned code warning and allow the download to continue. 7. Restart Eclipse when prompted. LOCATING THE SDK One more step and you’ll be able to create a project. You’ll need to tell Eclipse where to find your Android SDK. 1. Start Eclipse. You should be staring at the helpful Welcome screen. 2. Choose File > Preferences. If everything you’ve done thus far is working, you should see an Android option in the list on the left. 3. Click Android. NOTE: If you’re having trouble installing the Eclipse plug-ins, make sure you have an active Internet connection. Try using “http” instead of “https” for the plug-in URL. If all else fails, head over to http://developer.android.com/sdk/eclipse-adt.html#installing, where you’ll find a few more helpful debugging steps. CONFIGURING ECLIPSE 9 4. In the SDK Location field, enter the location to which you installed the SDK. Figure 1.4 shows what it looks like on my Mac. 5. Click Apply. In the large white box (which previously displayed “No target available”), you should now see a list of available SDK platforms. If you’re not seeing the list, then something isn’t right. Head back to the “Down- loading a Package” section and see what needs sorting out. CREATING AN EMULATOR Although I said you had only one more step before you could create a project, and that is true, you still need to create an emulator on which to run the project. So hang in, you’re almost there. 1. With Eclipse running, click the icon on the top bar. Or, if you’re a command-line junkie, run android in the shell (I’m going to assume you were able to add it to your path). FIGURE 1.4 Tell Eclipse where to find the Android SDK. 10 CHAPTER 1 GETTING STARTED WITH ANDROID This screen should look familiar, because you just used it to install one or two application platforms. Now you’re back to make a new virtual device. 2. With the Android SDK Manager open, make sure the Virtual Devices tab is selected and click New. A new emulator dialog will pop up. 3. In the Name field, give your emulator a name; it’s best to give it one that helps distinguish it from any others. You will have collected several emula- tors before publishing your first application. 4. From the Target drop-down menu, specify which SDK you want to target. It’s simplest right now to start with Gingerbread (2.3.3), but everything will still work on Ice Cream Sandwich (4.0). 5. In the SD Card field, select the Size radio button and enter a small size. 6. In the Skin section, select the Built-In radio button and choose Default WVGA800 from the drop-down menu. The completed screen should look like Figure 1.5. FIGURE 1.5 Configuring a new Android Virtual Device (AVD). CONFIGURING ECLIPSE 11 7. Click Create AVD and do a little dance next to your desk (or don’t, it’s up to you). 8. Select your new emulator and click the Start button to get it running. The laborious process of spinning up a new instance of the virtual device will begin. WORKING WITH YOUR ANDROID PHONE In almost all cases when I have an actual Android device, I’ll do development on it over the emulator. One of the wonderful things about Android is how utterly simple it is to connect and work with nearly any Android phone. Here’s what you’ll need to do if you want to start working with your own device. 1. Find the USB cable that came with your phone, and plug it into your computer. 2. On your home screen, press the menu bar and go to Settings > Applica- tions > Development and enable USB debugging by selecting the check box. 3. If you’re on a Windows machine, you may need to install the general USB drivers. You can find them at http://developer.android.com/sdk/win-usb.html. 4. If you’ve finished everything correctly, you should see a little bug icon in the notification bar on your device. Your phone will work in exactly the same way an emulator would. NOTE: Pro emulator tip: Once you start an instance of the emulator, you don’t ever have to start it up again. Reinstalling the application does not (as it does with many other systems) require you to spawn a new instance of the emulator. 12 CHAPTER 1 GETTING STARTED WITH ANDROID Congratulations! If you’ve followed every step thus far, you have your very own shiny emulator or connected device, your Android SDK is correctly installed, and you’re ready to rock and roll. Take a minute to bask in your own glory and play around with your new emulator (Figure 1.6) before moving on to the next section, which is about creating applications. FIGURE 1.6 Your shiny new emulator. TIP: The emulator is a full Linux VM and can be a little heavy on the system resources (especially while Eclipse is running), so make sure your development machine has plenty of RAM. CONFIGURING ECLIPSE 13 CREATING A NEW ANDROID PROJECT Google has provided a few helpful ways to create a new Android project. 1. Start Eclipse if it isn’t already running. 2. Choose File > New > Project. You should see the New Project screen (Figure 1.7). 3. Click Next, and Android’s friendly project creation wizard will start (Figure 1.8). Let’s go over what each field means to your project as you complete them. FIGURE 1.7 Select the project type here (Android Project). FIGURE 1.8 Enter all the pesky details for your project here. NOTE: If you’re not seeing the Android folder, you’ll need to make sure you’ve correctly installed the Android Eclipse plug-in. Head back to “Configuring Eclipse” and see where things may have gone awry. 14 CHAPTER 1 GETTING STARTED WITH ANDROID 4. Enter a name for your project in the Project Name field. This is how Eclipse keeps track of your project. Further, it will create a folder with this name and put all your project files into it. The project name will not show up anywhere on the Android device once you install. The project name is something that really only matters to Eclipse, so I tend to pick descriptive names for projects. 5. In the Build Target section, select the version of Android you’re targeting. Newer versions of Android always support applications built through older SDKs. They accomplish this with what’s called compatibility mode. For now, try to target the most advanced version you can. 6. In the Application Name field, enter the full name of your application. This is what will show in the app drawer after you have installed your app. 7. In the Package Name field, enter the Java package where you will place your first activity. 8. Select the Create Activity check box and enter a name for your new activity in the text box. This step creates a new class with this name, so Java class naming conven- tions apply. In Chapter 2, you’ll learn more specifics about what activities are and how they work. 9. Click Finish and you should be off to the races! Now that you have a project, let’s get it running. CREATING A NEW ANDROID PROJECT 15 CREATING A PROJECT FROM THE COMMAND LINE If you prefer to work from the command line, you can simply enter the following three commands and move on with your day: ᭿ android create project -n MyFantasticSimpleProject -t 9 -p myProjectDirectory -k com.haseman.fantasticProjctPackage -a NewActivity ᭿ cd myProjectDirectory ᭿ ant install These commands create a new project and install a new application on an Android device. Assuming that you didn’t run into any errors, you should find your sample app in the emulator’s app drawer. 16 CHAPTER 1 GETTING STARTED WITH ANDROID RUNNING A NEW PROJECT Follow these steps to get your project running: 1. If your emulator isn’t running, fire it back up. You need to make sure the IDE is in communication with the emulator; they frequently lose touch with each other. If you’re using a device, make sure it’s showing up cor- rectly here as well. 2. Open the DDMS perspective by choosing Window > Open Perspective > Other. You should see a little android next to the DDMS option. 3. Open the DDMS perspective. Under the Devices tab, you should see an entry for your emulator or device. 4. From the Run menu in Eclipse, choose “Run last launched” or Run. Eclipse may ask you to confirm that the app is indeed an Android project. Android will compile, package, install, and run the application on your emulator or device. If you can see the app running on your phone, congrats! You’ve now officially created an Android application. TIP: Command-line users can see DDMS by running . . . wait for it . . . ddms on the command line. RUNNING A NEW PROJECT 17 TROUBLESHOOTING THE EMULATOR If you’re sure your emulator is running, but it refuses to display in the list of devices, you may need to restart the Android Debug Bridge (ADB). Doing this requires get- ting into the terminal a little bit. 1. Open a terminal and change directories to the platform-tools folder inside your Android SDK folder. For me, the command looks like cd ~/Documents/ android_sdk/platform-tools. 2. Run adb kill-server and count to 15. 3. Run adb start-server. When you run the start command, you should see the following lines: * daemon not running. starting it now on port 5037 * * daemon started successfully * 4. Switch back to your DDMS perspective; you should see the virtual device listed in the devices window. 5. Switch back to the Java perspective and, from the Run menu, select . . . wait for it . . . Run. It will ask you what kind of project it is. 6. Select Android. It may ask you which device you’d like to run your project on. Eclipse may also want to know which device you’d like to run your project on. 7. If your emulator isn’t running, this will be your chance to start a new one. Otherwise, select your Android Virtual Device that is already running and click OK. Switching back to the emulator should show something close to Figure 1.9. Although it doesn’t do much, you’ve successfully created and run your first Android application. As Confucius said, a journey of a thousand miles begins with a single step. 18 CHAPTER 1 GETTING STARTED WITH ANDROID WRAPPING UP This chapter covered downloading, installing, configuring, creating, and running Android applications. You now have the very basic tools that you’ll need to continue with this book. Feel free, if you’re struggling with the topics in the later chapters, to refer back to this chapter as needed. FIGURE 1.9 Your very first Android application, running on the emulator! WRAPPING UP 19 2 EXPLORING THE APPLICATION BASICS I’m sure you’re ready to roll up your sleeves and write more code. However, there are a few topics in the realm of theory and design to cover in detail first. In this chapter, we’ll cover the basics of some essential building blocks, including the files, parts, and terms that make up a simple Android application; the Activity class that controls a single screen; the Intent class, Android’s powerful communications class; and the Application singleton class that can be accessed from all your components. I recommend you open Eclipse and follow along as I cover the working parts of an Android application. I’ll be using the Android project with the main activity, called MyActivity, that you created in Chapter 1. 21 ll u er, there are a few topics in the gn to cover in detail first. In this up your sleeves annddddddd there are a few topics in the Any mobile application, in its most basic form, consists of a single screen that launches by clicking an icon on the device’s main screen. When the SDK creates a basic Android project, it also creates several files and important directories. As with any project, before you start building the structure it’s important to at least take a quick look over the blueprints. Here are the file and folders that make up your Android project structure. ᭿ AndroidManifest.xml ᭿ /res ᭿ /src Throughout the rest of this chapter, I’ll refer to the manifest and these folders. THE MANIFEST The AndroidManifest.xml file is your portal to the rest of the phone. In it, you’ll describe which of your components should receive what events. You’ll also declare, in the manifest file, what hardware and software your app will need permission to access. First, let’s take a look at the declaration in the AndroidManifest.xml file: There are a few noteworthy items in this code. The package definition tells Android in which Java package to look for the class files that make up the compo- nents of your application. The next two variables are not particularly important right now, but they will become vital once you’re ready to ship your application to the Android Market. The versionCode is the number that helps the Market alert users that an update is available. The versionName is a string that the application menus and Market display to the user as the current version of your app. Your application can have only one AndroidManifest.xml file. Henceforth, I’ll refer to this file and concept simply as the manifest. THE FILES 22 CHAPTER 2 EXPLORING THE APPLICATION BASICS THE ACTIVITY CLASS In a typical Android application, activities are the backbone of the operation. Essen- tially, their purpose is to control what is displayed on the screen. They bridge the gap between the data you wish to display and the UI layout files and classes that do the work of displaying the data. If you’re familiar with the popular Model-View- Controller (MVC) architecture, the activity would be the control for a screen. Here’s what the activity declaration looks like in the manifest file: The android:name tag tells the system what to place on the end of your package (from the manifest declaration) to find your class definition. For example, in my sample project at com.haseman.peachPit.MyActivity, the class loader will look to find a class that extends the Activity class. In order to be found, the file must reside under the src/com/haseman/peachPit directory. This is standard operating procedure for the language that Android uses. WATCHING THE ACTIVITY IN ACTION The activity, if used correctly, is an object that specifically controls a single screen. Let’s talk about this mythical activity in terms of a real-world RSS news feed reader as a case study that can quickly explain what pages of theory would often miss. A developer typically uses one activity to list all feeds to which a user has subscribed. When a user taps a feed, the developer uses a second activity to display a list of available articles for that particular news feed. Lastly, when a user clicks a particular story, the developer uses a third activity to display article details. It’s easy to see how activities fill a certain role (subscription list, article list, article detail). At the same time, the activities are general, in that the article list should be able to display a list of articles from any RSS feed, and the article details activity should show the details from any article found through an RSS reader. THE ACTIVITY CLASS 23 IMPLEMENTING YOUR OWN ACTIVITY In most cases, the best way to understand something is to use it. With that in mind, let’s add a new activity to the project you created in Chapter 1. This will explain how the activity works, its lifecycle, and what you need to know while working with it. Here are the general steps you’ll need to follow: 1. Add an entry for the new activity into your manifest. 2. Create a new class that extends the Activity class. 3. Create a new file containing the XML layout instructions for this new activ- ity, and add a new string literal for the layout to display (don’t worry, this sounds a lot harder than it actually is). 4. When all the files are in place, you’ll need to actually launch this new activ- ity from your existing one. THE MOST BASIC OF ACTIVITIES In its simplest form, an activity is an object that extends the Activity class. It should, but doesn’t have to, implement the onCreate method. Here’s what your activity looks like by default when you create a new project: public class MyActivity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } } In this code, the device calls the onCreate method as the activity is starting. onCreate tells the UI system that the setContentView method specifies the main layout file for this activity. Each activity may have one and only one content view, 24 CHAPTER 2 EXPLORING THE APPLICATION BASICS so once you set it, it can’t be changed. This is how the Android SDK forces you to use a new activity for each screen, because each time you want to change your root content view, you’ll need a different activity. TELLING ANDROID ABOUT YOUR FRIENDLY NEW ACTIVITY The Android system needs to know where to find your new activity when it comes time to load and launch it. 1. Open up the AndroidManifest.xml file in Eclipse. 2. Add the following line inside the tag and directly after the closing tag of the previous declaration: This little line tells the system where to find the new activity in your appli- cation package. In the case of my demo, the class loader knows to look for the activity at com.haseman.peachPit.NewActivity. Next, you’ll need to put a file there for it to find. CREATING THE NEWACTIVITY CLASS There are several ways to create a new activity, but here is the easiest way to do it in Eclipse. 1. Right-click (or Control-click) the package name you’ve chosen (mine is com.haseman.peachPit). 2. Select New, then select Class. 3. Give the class a name in the dialog. A name is enough to create a new file. The file will be saved in your main package under the name you specified. In my demo, it is in my project under src/com/haseman/peachPit/NewActivity.java. Now that you have a class that extends an object, you’ll need to switch it over to extend an activity. THE ACTIVITY CLASS 25 4. Make the following highlighted change to your code: package com.haseman.peachPit; import android.app.Activity; import android.os.Bundle; public class NewActivity extends Activity{ public void onCreate(Bundle icicle){ super.onCreate(icicle); } } Notice that this code looks very similar to what is already in your existing activity. Let’s make it a little bit different. 5. In the res/values/strings.xml file, add the following highlighted lines in the tag under the existing strings: Welcome to the New Activity! In these lines, you told Android that you want a new string with the name new_activity_text that can be accessed through Android’s resource man- ager. You’ll learn much more about the contents of the /values folder in later chapters. Next, you need to create a layout file for your new activity. 26 CHAPTER 2 EXPLORING THE APPLICATION BASICS CREATING A NEW SCREEN LAYOUT Here’s how you create a new layout. 1. Create a new file named new_activity.xml inside the res/layout/ folder. It should sit next to the existing main.xml file (which is used by your existing activity). This new_activity.xml file should look almost exactly like main.xml, except you’ll need to add a reference to the string you just created. 2. Insert the highlighted line to create a reference to the string you just created. 3. Give this modified TextView an ID so your Java code can reference it (you’ll learn more about TextViews later; for now you should know that they’re Android views that show text on the screen): I will devote Chapter 3 to resource management and user interface design, but for now just keep in mind that the @ prefix is how you tell Android you want to reference an ID, string, or drawable that is defined elsewhere as a resource. Now that you have a new layout with its shiny new string, you’ll need to tell the NewActivity class that you want it to use this particular layout file. THE ACTIVITY CLASS 27 4. Add the following highlighted line to the onCreate method of your New Activity class: public void onCreate(Bundle icicle){ super.onCreate(icicle); setContentView(R.layout.new_activity); } setContentView is the method in which you tell Android which XML file to display for your new activity. Now that you’ve created a new class, string, and layout file, it’s time to launch the activity and display your new view on the screen. CATCHING KEYS The simple way to launch your new activity is to have the user press the center key on his or her device. If your phone doesn’t have a center key, you can easily modify the following code to accept any key you like. To listen for key events, you’ll need to extend the original activity’s onKeyDown method. Keep in mind that this is a simple example case. Launching a new activity when the user presses a single key prob- ably isn’t a very common use case in practice, but it makes for a good and simple example. Most new activities are started when a user selects a list item, presses a button, or takes another action with the screen. Here’s what your new version of onKeyDown should look like: @Override public boolean onKeyDown(int keyCode, KeyEvent event){ if(keyCode == KeyEvent.KEYCODE_DPAD_CENTER){ //Launch new Activity here! return true; } return super.onKeyDown(keyCode, event); } 28 CHAPTER 2 EXPLORING THE APPLICATION BASICS By declaring onKeyDown, you’re overriding the default key handler in order to take action specific to your own activity. It’s always a good idea to pass the incoming key to the parent class’s version of the method if it’s not something your activity handles on its own. Notice that when the keyCode matches the center button, you return true. This is how you tell the Android activity and views that the key has been correctly handled and shouldn’t be passed on to anyone else. Otherwise, you allow the activ- ity superclass to handle the key. This may not seem like a big deal now, but it will become much more important as your Android activities become more complex. LAUNCHING THE ACTIVITY Finally, it’s time to launch the new activity. This will start your brief foray into intents. Each new activity is started as the result of a new intent being dispatched into the system (which processes it and takes the appropriate action). In order to start the first activity, you’ll need a reference of your application context and the class object for your new activity. Let’s create the new intent first. 1. Place the following code into your onKeyDown key handling method: Intent startIntent=new Intent( this.getApplicationContext(), NewActivity.class); You’re passing the new intent an application context and the class object of the activity that you would like to launch. This tells Android exactly where to look in the application package. There are many ways to create and interact with intents; this is, however, the simplest way to start up a new activity. Once the intent is properly constructed, it’s simply a matter of telling the Android system that you’d like to start the new activity. 2. Put the following line into your key handling method: startActivity(startIntent); THE ACTIVITY CLASS 29 Your onKeyDown handler should look like the following: public boolean onKeyDown(int keyCode, KeyEvent event){ if(keyCode == KeyEvent.KEYCODE_DPAD_CENTER){ Intent startIntent=new Intent(this, NewActivity.class); startActivity(startIntent); return true; } return super.onKeyDown(keyCode, event); } TRYING IT OUT If you’re running Eclipse and you’ve been coding along with me, it should now be a simple matter of spinning up the emulator and installing your new activity (the steps for which you should remember from Chapter 1). Once your new application has launched, press the center key to see the results of all your labor (Figure 2.1). Now that you know how to create and launch a new activity, it’s time to discuss how that process works. You’ll need to understand, for the purposes of UI layout and data management/retention later, what methods are called each time one of your activities makes its way onto, and off of, the screen. FIGURE 2.1 Here is your new activity! NOTE: Throughout this whole process, the original activity has never once had access to the instance of the new activity. Any information that might pass between these two activities must go through the intermediary intent. You’ll learn how this is done in the next section. 30 CHAPTER 2 EXPLORING THE APPLICATION BASICS GETTING INTENTS Intents can take a myriad of forms. You use them anytime you need to start an activity or service. Further, you’ll frequently use intents for system-wide communication. For example, you can receive notifications about power system changes by registering for a widely published intent. If one of your activities registers for an intent in the manifest (for example, com.haseman.peachPit.OhOhPickMe), then any applica- tion anywhere on the phone can, if you make your activity public, launch directly to your activity by calling startActivity(new Intent(“com.haseman.peachPit.OhOhPickMe”)); THE LIFE AND TIMES OF AN ACTIVITY It’s good to know early on that each activity lives a very short but exciting life. It begins when an intent that your activity is registered to receive is broadcast to the system. The system calls your activity’s constructor (while also starting your application as necessary) before invoking the following methods on the activity, in this order: 1. onCreate 2. onStart 3. onResume When you implement an activity, it’s your job to extend the methods that make up this lifecycle. The only one you are required to extend is onCreate. The others, if you declare them, will be called in the lifecycle order. Your activity is the top visible application, can draw to the screen, will receive key events, and is generally the life of the party. When the user presses the Back key from the activity, these corresponding methods are called in the following order: 1. onPause 2. onStop 3. onDestroy THE ACTIVITY CLASS 31 THE SHORT, BRUTAL LIFE OF THE ACTIVITY An activity’s life is an incredibly short one. They are constantly created and destroyed, so it’s very important that you save no data in them that has any relevance outside the screen your activity will control. The following are all valid actions that will result in the destruction of any activity: 1. The user rotated the device from portrait to landscape or vice versa. 2. The activity is no longer visible onscreen or the system is low on resources. 3. It’s Tuesday. 4. The user has pressed the Back or Home buttons and left your application. Again, make sure the data members of your activity pertain only to the ele- ments on the screen. Further, don’t expect the activity to save any data for you. You’ll learn strategies to handle this in later chapters. After these methods have executed, your activity is closed down and should be ready for garbage collection. In order to make sense of the activity’s flow, let’s quickly look over each lifecycle method in detail. Remember that you must evoke the superclass call in each of these methods (often before you do anything else) or Android will throw exceptions at you. PUBLIC VOID ONCREATE(BUNDLE ICICLE) Android will call your declaration of this method as your activity is starting. Remem- ber, however, that during the run of your application you may go through several instances of each activity. If, for example, the user changes the screen orientation from landscape to portrait, your activity will be destroyed and a new instance of the same activity will be created and initialized. NOTE: onCreate is the only one of the application lifecycle methods that you must implement. I’ve found, in most of my work with Android, that I only end up implementing one or two of these methods depend- ing on what each activity is responsible for. 32 CHAPTER 2 EXPLORING THE APPLICATION BASICS If the title, say, for your activity is dynamic but will not change after the activity is started, this method would be where you’d want to reach into the view hierarchy and set up the title. This method is not the place to configure data that could change while the app is in the background or when another activity is launched on top of it. Further, if your app is running in the background and the system is running low on resources, your application may be killed. If that happens, the onCreate method will be called on a new instance of the same activity when your applica- tion returns to the foreground. The onCreate method is also your one and only chance to call setContentView for your activity. This, as you saw earlier, is how you tell the system what layout you’d like to use for this screen. You call setContentView once you can begin set- ting data on the UI. This could be anything from setting the contents of lists to TextViews or ImageViews. PUBLIC VOID ONSTART() When starting up, your onStart method is called immediately after onCreate. If your app was put in the background (either by another application launching over yours or the user pressing the Home button), onStart will be called as you resume but before the activity can interact with the screen. I tend to avoid overriding onStart unless there’s something specific I need to check when my application is about to begin using the screen. PUBLIC VOID ONRESUME() onResume is the last method called in the activity lifecycle as your activity is allowed access to the screen. If UI elements have changed while your activity was in the background, this method is the place to make sure the UI and phone state are in sync. When your activity is starting up, this method is called after onCreate and onStart. When your activity is coming to the foreground again, reguardless of what state it was in before, onResume will be called. HOORAY, YOUR ACTIVITY IS NOW RUNNING! After all this setup, configuration, and work, your activity is now visible to the user. Things are being clicked, data may be parsed and displayed, lists are scrolled, and things are happening! At some point, however, the party must end (perhaps because the user pressed the Back key) and you’ll need to wind things down. THE ACTIVITY CLASS 33 ONPAUSE( ) onPause is the first method called by the system as your application is leaving the screen. If you have any processes or loops (animations, for example) that should be running only while your activity is onscreen, the onPause method is the per- fect place to stop them. onPause will be called on your activity if you’ve launched another activity over the one you’re currently displaying. Keep in mind that if the system needs resources, your process could be killed anytime after the onPause method is called. This isn’t a normal occurrence, but you need to be aware that it could happen. The onPause method is important because it may be the only warning you get that your activity (or even your entire application stack) is going away. It is in this method that you should save any important information to disk, your database, or the preferences. Once your activity has actually left the screen, you’ll receive the next call in the activity lifecycle. ONSTOP( ) When Android calls your onStop method, it indicates that your activity has officially left the screen. Further, onStop is called when the user is leaving your activity to interact with another one. This doesn’t necessarily mean that your activity is shutting down (although it could). You can only assume that the user has left your activity for another one. If you’re doing any ongoing process from within your activity that should run only while it’s active, this method is your chance to be a good citizen and shut it down. ONDESTROY( ) onDestroy is your last method call before oblivion. This is your last chance for your activity to clean up its affairs before it passes on to the great garbage collec- tor in the sky. Any background processes that your activity may have been running in the back- ground (fetching/parsing data, for example) must be shut down on this method call. However, just because onDestroy is called doesn’t mean that your activity will be obliterated. So if you have a thread running, it may continue to run and take up system resources even after the onDestroy method is called. 34 CHAPTER 2 EXPLORING THE APPLICATION BASICS BONUS ROUND—DATA RETENTION METHODS As mentioned earlier, your process can be killed at any point after onPause if the system needs resources. The user, however, shouldn’t ever know that this culling has occurred. In order to accomplish this, Android gives you two chances to save your state data for later use. ONSAVEINSTANCESTATE(BUNDLE OUTSTATE) This method passes you a bundle object into which you can put any data that you’d need to restore your activity to its current state at a later time. You’ll do this by calling something like outState.putString or outState.putBoolean. Each stored value requires a string key going in, and it requires the same string key to come back out. You are responsible for overriding your own onSaveInstanceState method. If you’ve declared it, the system will call it; otherwise, you’ve missed your chance. When your previously killed activity is restored, the system will call your onCreate method again and hand back to you the bundle you built with onSaveInstanceState. onSaveInstanceState will only be called if the system thinks you may have to restore your activity later. It wouldn’t be called if, for example, the user has pressed the Back key, as the device clearly has no need to resume this exact activity later. As such, this method is not the place for saving user data. Only stash temporary information that is important to the UI on this particular instance of the screen. ONRETAINNONCONFIGURATIONINSTANCE( ) When the user switches between portrait and landscape mode, your activity is destroyed and a new instance of it is created (going through the full shut- down-startup cycle of method calls). When your activity is destroyed and cre- ated specifically because of a configuration change (the device rotation being the most common), onRetainNonConfigurationInstance gives you a chance to return any object that can be reclaimed in your new activity instance by calling getLastNonConfigurationInstance. This tactic helps to make screen rotation transitions faster. Keep this in mind if it takes your activity a significant amount of time to acquire data that it plans on displaying to the screen. Instead, you can get the previously displayed data by using getLastNonConfigurationInstance. THE ACTIVITY CLASS 35 KEEP IT SIMPLE, SMARTY By now you know that activities can be killed off with very little notice. The onSaveInstanceState gives you a chance to save primitives for later use. This means, unequivocally, that your entire activity must be able to collapse all its important information into a series of primitives. This further reinforces the notion that activities must be very simple and cannot contain any complex data important to the application outside itself. Avoid keeping large Java col- lections filled with data in your activity, as it may be terminated with very little notice. You should now have a basic understanding of ᭿ Steps for creating a new activity ᭿ How an activity is started ᭿ The lifecycle of an activity You have what you need to keep up as I go over more complex topics in later chapters. Fear not, I’ll come back to the activity in no time. 36 CHAPTER 2 EXPLORING THE APPLICATION BASICS THE INTENT CLASS An intent is a class. Intents, in the Android platform, make up the major commu- nication protocol for moving information between application components. In a well-designed Android application, components (activity, content provider, or service) should never directly access an instance of any other component. As such, intents are how these pieces are able to communicate. A good half of this book could be dedicated to the creation, use, and details of the Intent class. For the sake of brevity and getting you up and running as fast as possible, I’ll cover only a few basics in this chapter. Look for intents throughout the rest of this book. They’re probably the most often used class in Android as a whole. There are two main ways to tell the Android system that you’d like to receive intents sent out by the system, by other applications, or even by your own app: ᭿ Registering an in the AndroidManifest.xml file ᭿ Registering an IntentFilter object at runtime with the system In each case, you need to tell the Android system what events you want to listen for. There are huge heaping numbers of ways to send intents as well. You can broad- cast them out to the system as a whole, or you can target them to a specific activity or service. However, in order to start a service or activity, it must be registered in the manifest (you saw an example of this in the previous demonstration on start- ing a new activity). Let’s take a look at how to use intents in practice. MANIFEST REGISTRATION Why not register everything at runtime? If an intent is declared as part of your manifest, the system will start your component so that it will receive it. Registra- tion at runtime presupposes that you are already running. For this reason, anytime you want your application to awaken and take action based on an event, declare it in your manifest. If it’s something your application should receive only while it’s running, register an IntentFilter (it’s an intent-filter when declared in XML, but an IntentFilter in your Java code) once your particular component has started. THE INTENT CLASS 37 Let’s go back to the initial application and look again at the activity’s entry in the manifest: The android.intent.action.MAIN declaration tells the system that this activity is the main activity for your application. No parameters are needed to start it. It’s a good idea to list only one activity as MAIN in the manifest. This is also how adb (the Android debug bridge), when you run your application from Eclipse, knows which activity to start up. The android.intent.category.LAUNCHER category tells the system that the enclosing activity should be launched when your icon is clicked on the main phone’s application dock. Further, it tells Android that you’d like the icon to appear in the app launcher drawer. This is an example of an intent-filter that’s created for you by Android’s project creation tools. Let’s add one of our own. ADDING AN INTENT If you skipped the previous section about the Activity class, now may be a good time to go back and at least skim over the code. In that section, I showed you how to declare and launch a simple new activity. What I didn’t show you, however, was how to make that activity accessible to the system as a whole by declaring an for it within your manifest. Let’s do that now. 1. Add an intent-filter to the NewActivity declaration: 38 CHAPTER 2 EXPLORING THE APPLICATION BASICS In this code, you’ve registered for intents containing the com.haseman. PURPLE_PONY_POWER action and set the intent-filter category to default. Now, lest you think I’m a crazed children’s toy enthusiast, I’ve used this rather absurdist action string to demonstrate a point—namely, that the only requirement for the action string is that it be unique for your particular component. In the previous section, I showed you how to launch the new activity by using the following lines: Intent startIntent=new Intent(this, NewActivity.class); startActivity(startIntent); This works, but it has one major limitation: It cannot be launched out- side your own application’s context. This renders useless one of the most powerful features that the activity-intent model has to offer. Namely, any application on the device, with the right intent, can use components within your application. Now that you’ve added the to the sample project manifest, you can launch this particular activity anywhere with the following code: Intent actionStartIntent= new Intent p (“com.haseman.PURPLE_PONY_POWER”); startActivity(actionStartIntent); Notice a very important difference between this code and the listing above it. When you create the intent in this example, you’re not required to pass in a Context object (the bundle of information that is required to communicate with the system at large). This allows any application, with knowledge of the required intents, to start the NewActivity class. THE INTENT CLASS 39 2. Add the highlighted code to the onKeyDown handler to launch the same activ- ity in a different way. Here’s how the new OnKeyDown method should look: public boolean onKeyDown(int keyCode, KeyEvent event){ if(keyCode == KeyEvent.KEYCODE_DPAD_CENTER){ Intent startIntent=new Intent(this, p NewActivity.class); startActivity(startIntent); return true; } if(keyCode == KeyEvent.KEYCODE_DPAD_DOWN){ Intent actionStartIntent= new Intent(“com.haseman.PURPLE_PONY_POWER”); startActivity(actionStartIntent); } return super.onKeyDown(keyCode, event); } Now, when you press the down key in the sample application, you’ll see the same activity launching using this new manifest-declared intent-filter. If you’ve misspelled the intent’s action string or neglected to add the default category to your intent-filter, you may get an android.content.Activity NotFoundException. This exception will be thrown by the startActivity method anytime you create an intent that the system cannot connect to an activity listed in a manifest on the device. Registering for intent filters is not only the purview of the activity. Any Android application component can register to be started when an intent action is broadcast by the system. 40 CHAPTER 2 EXPLORING THE APPLICATION BASICS MANY INTENTS, ONE ACTIVITY One activity may register to receive any number of events. Typically, sending an intent is akin to telling the activity “do this one thing!” That “one thing” can be anything from editing a file to displaying a list of pos- sible files or actions. Again, as we’ve discussed, it’s important to limit the scope of your activity, so register- ing for only one intent is often a good idea. However, because your activity could be registered for more than one intent, it’s a good idea to call getIntent inside your onCreate method and check why you’re being started so you can take the right action (by calling getAction). LISTENING FOR INTENTS AT RUNTIME Another method for receiving events that pertain only to your application or for receiv- ing events broadcast by the Android system itself is to listen for the intents at runtime. Let’s say that your activity would like to show a special screen or take a custom action when the user enables Airplane mode. To do this, you’ll need to create a temporary IntentFilter and an inner BroadcastReceiver object instance. CREATE A RECEIVER Let’s add the runtime BroadcastReceiver to the MyActivity class. A Broadcast Receiver is, as you can probably guess, an object with a single onReceive method. Change the MyActivity class to look like the following: public class MyActivity extends Activity { private BroadcastReceiver simpleReceiver=new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { if(intent.getAction().equals( Intent.ACTION_AIRPLANE_MODE_CHANGED)){ Toast.makeText(context, R.string.airplane_change, Toast.LENGTH_LONG).show(); } } }; //Rest of the Activity is here. } THE INTENT CLASS 41 In this code, you are creating a locally accessible receiver for use within the activity. When the system calls onReceive, you’ll need to check what the intent’s action is. This is a good idea, as BroadcastReceiver could register for any number of different intents. When you receive the event that you’re looking for, you’ll use Android’s Toast API to print a simple message on the screen (in this case, the contents of the string named airplane_change). In practice, this might be the time to show a screen indicating that network connectivity is required for the application to run correctly. TELL ANDROID WHAT YOU WANT TO HEAR Now that you’ve created a BroadcastReceiver, you can register it with the system. I’ll show you the code first and then go over what’s happening: public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); registerReceiver(simpleReceiver, intentFilter); } A TOAST? A toast is a short message shown to the user in a small pop-up along the bottom of the screen. This is a reference, as far as I can tell, to the short speech given before glasses are raised, tapped together, and then partaken of. As always with toasts, the shorter and simpler the better. 42 CHAPTER 2 EXPLORING THE APPLICATION BASICS Again, this is in the original MyActivity class made by the SDK when you cre- ated the project. 1. In the onCreate method, create an intent filter and add the action Intent. ACTION_AIRPLANE_MODE_CHANGED to it. 2. Add as many actions to this intent filter as you wish. When your receiver is called, you’ll have to sort out which intent actually triggered the Broadcast Receiver’s onReceive method by calling getAction() on the intent. 3. Test the code by holding the power button down; this will pop up a dialog with several options. 4. Enable Airplane mode. If you’ve done everything right so far, you should see a small message pop up along the bottom of the screen with your alert message in it. This is going to be the primary way in which your applications will listen for information on the status of the system. Everything from the status of the battery to the status of the Wi-Fi radio is at your fingertips with this tool. You can find out more about what activities you can monitor, with what permissions, by looking in the Android SDK documentation. REMEMBER TO STOP LISTENING For every runtime registration that you create, you must also unregister it. If you would like to receive the events only when your activity is visible, onPause is the best place to turn off the receiver. If you’d like to listen for as long as your activity is running, even if it’s not visible, you’ll want to unregister in onDestroy. Wherever you decide to stop listening, simply call unregisterReceiver (a method implemented by your superclass) and pass in the BroadcastReceiver you created earlier, like this: @Override public void onDestroy(){ super.onDestroy(); unregisterReceiver(imageReceiver); } THE INTENT CLASS 43 CREATING SELF-CONTAINED BROADCAST RECEIVERS A broadcast receiver doesn’t have to exist inside an activity. You can register a receiver if you want to know about a system event but might not need to start your full application when it occurs. BroadcastReceivers can be registered on their own under the tag. In practice, I use these as a way to receive information about the system that may not require showing something to the user. Starting an activity only to shut it down if it’s not needed is much more resource expensive than grabbing the broadcast intent with a receiver and then starting up an activity only when needed. HANDLING COLLIDING ACTIVITIES You may be thinking to yourself “Self, what happens when more than one activ- ity is registered for the same intent?” This is a very interesting question, one that Android resolves simply by asking the user. If two activities listen for the same intent in their manifests, and an application attempts to start an activity with that intent, the system will pop up a menu giving users a list of possible applications to choose from (Figure 2.2). You’ve probably seen similar behavior hundreds of times on your desktop com- puter, such as when opening a file and being given a choice about which application you’d like to open it with. FIGURE 2.2 Do you want to open that YouTube link in the browser or the app? 44 CHAPTER 2 EXPLORING THE APPLICATION BASICS This notion of many activities registering for the same intent can have delightful side effects. In Android, any application can register to share media with a given MIME time by using the android.intent.action.SEND action. Figure 2.3 is what the Share tab on my phone looks like when I press it in the image gallery. It is this ability to register for similar intents that allows seamless interaction as each application registering this intent is given an entry on the Share menu. Click- ing an entry in this list will start the registered activity and pass along as an extra the location at which the image can be accessed. What is an extra? Good question. MOVING YOUR OWN DATA One of the major features of the intent is the ability to package and send data along with it. One activity should never directly manipulate the memory of another. However, they still must have a way to communicate information. This commu- nication is accomplished with the help of the intent’s Extra bundle. The bundle can hold any number of string-primitive pairs. Perhaps the best way to illustrate this concept is with some code and an example. Earlier, I showed you how to start a new activity by using an action-based broadcast intent. FIGURE 2.3 What happens when you share my funny- looking Android avatar? THE INTENT CLASS 45 Add the following highlighted code to the onKeyDown listener that you’ve dealt with before: public boolean onKeyDown(int keyCode, KeyEvent event){ //...previous keycode code skipped... if(keyCode == KeyEvent.KEYCODE_DPAD_DOWN){ Intent actionStartIntent= new Intent(“com.haseman. p PURPLE_PONY_POWER”); actionStartIntent.putExtra(“newBodyText”, “You Pressed the Down Key!”); startActivity(actionStartIntent); } You’re adding a string payload to the intent before using it to start an activity. Whoever receives the intent will be able to pull this string out (assuming they know it’s there) and use it as they see fit. Now that you know how to attach the data, let’s take a look at an example of retrieving and using the string in NewActivity’s onCreate method: public void onCreate(Bundle icicle){ super.onCreate(icicle); setContentView(R.layout.new_activity); Intent currentIntent = getIntent(); if(currentIntent.hasExtra(“newBodyText”)){ String newText = currentIntent.getExtras(). p getString(“newBodyText”); TextView bodyView = (TextView)findViewById( R.id.new_activity_text_view); bodyView.setText(newText); } 46 CHAPTER 2 EXPLORING THE APPLICATION BASICS In the highlighted code, I’m getting the intent that was responsible for starting my NewActivity by calling getIntent. Next, I’m checking if this intent actually contains the newBodyText extra. Keep in mind that the intent may not contain the extra. If you forget to check for this case, you’ll quickly find yourself inundated with NullPointerExceptions. If the extra is there, I’ll pull it out and set the string as the new text in my display. The last two lines obtain a reference to the screen’s text view and change the text to be the contents of the extra. Don’t worry about the mechanics of that particular operation right now; you’ll learn more about this topic in depth later. REVIEWING INTENTS You’ve learned how to register for, create, and use the basic functionality of an intent. As you now know, they can be registered for in the manifest or at runtime. They can be sent by any application on the phone, and any number of application components can register for the same intent. The goal in this section was to get you started on the care and feeding of Android intents. In future chapters and tasks, you’ll work with intents again in many dif- ferent contexts. THE INTENT CLASS 47 THE APPLICATION CLASS Typically, an Android application is a collection of activities, broadcast receivers, services, and content providers. The Application class is the glue that binds all these disparate pieces into a singular, unified entity. Every time a content provider, activity, service, or intent receiver in your manifest is initialized, an Application class is also spun up and available to it. THE DEFAULT APPLICATION DECLARATION Looking in the AndroidManifest.xml file, you’ll see a typical Application declara- tion that looks like the following: Here you can see the tag. This part of the manifest typically contains information relevant to your application at large. android:icon tells the system what icon to display in the main application list. android:label in this case refers to another entry in the strings.xml file you were editing earlier. CUSTOMIZING YOUR OWN APPLICATION Adding your own application is very similar to the steps you’ve already gone through to add a new activity. 1. Add a name field to the existing AndroidManifest.xml declaration. 2. Create a new class in your package that extends the Application class. 3. Profit! Let’s go over steps 1 and 2 in depth. You’re on your own for step 3. THE NAME When it comes to the manifest, android:name refers not to the name of the object being described, but to the location of the class in your Java package. The Application declaration is no exception. Here’s what the opening tag of the application should look like with the new declaration: 48 CHAPTER 2 EXPLORING THE APPLICATION BASICS In this declaration, you tell the system what icon you want to represent your application on the Android application drawer. Once again, the class loader will look for your Application class by appending the contents of android:name to the end of your package declaration within the opening tag. Now you’ll need to actually create this class to keep the class loader from getting unhappy. THE APPLICATION CLASS Here’s what you’ll need, at a very basic level, to have an Application of your very own: import android.app.Application; public class SampleApplication extends Application{ public void onCreate(){ super.onCreate(); } } The Application can be a very simple class. It’s hard to understand what the Application can do for you until you consider a few things: ᭿ Activities are very transient. ᭿ Activities have no access to each other’s memory, and they should com- municate through intents. ᭿ As activities are constantly being stopped and started for a variety of reasons, there’s no way for your activity to know if it’s being started for the very first time in the run of your application. The Application class’s onCreate method, on the other hand, is called only when your app is being initialized. As such, it can be a good place to take actions that should happen only when your application is first started. THE APPLICATION CLASS 49 If you need a temporary holding pen for data that may span many activities, a data member that’s part of the Application can be a convenient place to store it. You must be very careful about adding data to the Application. Any single compo- nent declared in your manifest, from the simplest BroadcastReceiver to the most complex activity, will, before it’s created by the system, first create your Application object. This means you must make the Application’s onCreate method run as fast as you possibly can. ACCESSING THE APPLICATION All your broadcast receivers, services, activities, and content providers have a method called getApplication provided to them by the appropriate superclass. When invoked, getApplication will return a pointer to your Application object if you specified one in the manifest. Getting access to it, now that you’ve declared and created the class, is as simple as calling getApplication and casting the returned object to an instance of your own pointer. Here’s what it looks like: SampleApplication myApplication = (SampleApplication) getApplication(); That’s all there is to it. You can add public data members or context-sensitive methods to your own version of the Application, and with one call all your com- ponents will have access to the same object, like so: public class SampleApplication extends Application{ public String username; public void onCreate(){ super.onCreate(); } } 50 CHAPTER 2 EXPLORING THE APPLICATION BASICS To access your newly added variable, simply do the object cast listed earlier: public void onCreate(Bundle bundle){ SampleApplication myApplication = (SampleApplication)getApplication(); myApplication.username = “sparks”; } Be sure that any data you put in the Application is relevant everywhere, because the overhead for allocating and initializing the Application can become a drag on startup times. WRAPPING UP Over the course of this chapter, I’ve exposed you to the fundamental building blocks of an Android application. I used examples to get you started on ᭿ The manifest ᭿ Creating and using your own activities ᭿ Sending, receiving, and taking advantage of intents ᭿ Creating your own Application object It’s my hope that through the rest of the book, you’ll be able to use the building blocks you’ve learned in this chapter to understand how an Android application functions. From here on out, I’ll be focusing more on how to do tasks rather than on the theories that back them. On that note, let’s start making screens that include more than just a single text view. WRAPPING UP 51 3 CREATING USER INTERFACES Creating an intuitive, good-looking interface is one of the most important aspects of a successful Android application. It doesn’t matter how wonderful your code is if the user cannot easily find and use the features you’ve worked so hard to create. While Android’s diversity may give your appli- cation access to a greater pool of devices, you must also contend with making sure your application correctly supports all those screen sizes. Fortunately, Android gives developers many tools to make the process as straightforward as possible. In this chapter, you’ll learn about all but one of the major building blocks for displaying infor- mation. The one major omission is the ListView class, which will be covered in a chapter of its own. 53 d-lo t aspects of a successful Androi atter how wonderful your code is ooking interface iiiissss spects of a successful Androidd No, this isn’t a television show where several women debate the merits of com- mon culture. The View class is the superclass for all the Android display objects. Each and every user interface (UI) class from the simple ImageView to the mighty RelativeLayout all subclass from this same object. In this section, you’ll learn the basics of creating, adding, and modifying your existing layouts using Java code and XML. You’ll also learn to create your own custom view. A view, at its very core, is simply a rectangle into which you can display something. Subclasses take many different forms, but they all need, simply, a space to show something to the user. CREATING A VIEW Creating a new view is something you’ve already done. In Chapter 1, you added a view to an XML layout file as part of exploring how to launch a new activity. At the time, I told you we’d get into the specifics of how these views were created and modified, and, well, now’s the time! Let’s take a look at the default views generated for you automatically when you create a new Android project. VIEWS IN XML Here’s what the default XML layout looks like in a new project: THE VIEW CLASS 54 CHAPTER 3 CREATING USER INTERFACES HEIGHT AND WIDTH ARE REQUIRED For now, it’s important to note that every single layout must have a value set for both its height and its width. Android may not fail to compile if you do not specify these values (as they could be updated at runtime), but if it starts to draw your views and the system height and width values are missing, then your application will crash. Question: Which of the two elements (LinearLayout and TextView) in this default XML layout are views? Answer: Both. All visual objects onscreen subclass from the View class. If you go high enough in the inheritance chain, you’ll find an “extends View” somewhere. In the default XML layout, the Android tools have added a simple TextView contained inside a LinearLayout. When displayed onscreen, the contents of the hello string will appear by default in the upper-left corner of the screen. I’ll discuss how to position visual elements onscreen later in this chapter. To display the XML layout onscreen, you need to call the setContentView() method and pass the name of the layout to the activity. In Eclipse, your code editor, it should look like this: @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } In this code, you’re telling the activity that you want it to inflate and render the main layout for this activity. By inflating, I mean the conversion from the XML in the project to a Java object that can be told to draw on the screen. You might be thinking, “Is it possible to build and display a layout and view within Java alone? Can I skip layout in XML entirely and go straight to the source?” Yes, you can, but in practice you shouldn’t. Even so, understanding how to build a layout without the XML will help you potentially modify any aspect of your layout at runtime. THE VIEW CLASS 55 VIEWS IN JAVA Anything you can lay out or build in XML, you can lay out and build also within the Java code itself; it’s just more complex. It’s important, however, to understand what Android is doing as it inflates and builds your layouts. Here’s what the Java code looks like to build the exact same user interface that Android generates for you in XML when you create a new project: public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(buildLayouts()); } public View buildLayouts(){ LinearLayout topView = new LinearLayout(getApplicationContext()); LayoutParams topLayoutParams = new FrameLayout.LayoutParams (LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); topView.setLayoutParams(topLayoutParams); TextView textView = new TextView(getApplicationContext()); LinearLayout.LayoutParams textLayoutParams = new LinearLayout.LayoutParams( LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); textView.setLayoutParams(textLayoutParams); textView.setText(R.string.hello); topView.addView(textView); return topView; } 56 CHAPTER 3 CREATING USER INTERFACES SPECIAL DIMENSIONS You are always required to give a height and width for every view in your hierarchy. You may use, for these definitions in particular, four different values. They are: ᭿ wrap_content makes the view big enough to match what it contains. This might mean different things to different views, but the concept remains the same. ᭿ fill_parent and match_parent values actually mean exactly the same thing. Namely, I want the dimensions of this view to match the dimen- sions of my parent view. ᭿ dip or dp stands for device-independent pixels. This is a value that will give you a consistent spacing regardless of the screen density (pixels per inch) of the device. On the Nexus 1 or Nexus S, 1 dp ~= 1.5 pixels. ᭿ px stands for pixels. There are times when exact pixel values are necessary. I advise against using this to declare screen locations, but it’s an option. Let’s look at what is happening in the Java code. Instead of calling setContent View on an ID from the R.java file, I’m passing it an instance that the LinearLayout object returned from the buildLayouts method. In the buildLayouts method, I’m first creating a new LinearLayout (passing in the application’s context) and a new LayoutParams object. To match what’s in the XML, the new LayoutParam is initialized with both the width and the height set to MATCH_PARENT. If you have done Android development before, you should know that MATCH_PARENT is exactly the same as the previously used FILL_PARENT. Once I have the layout parameters initialized for the top LinearLayout, I can pass them to the object with a setLayoutParams call. I’ve now got the LinearLayout configured, so it’s time to move on to building the TextView. This is a simple text view, so its layout parameters are very similar to those of its parent’s layout. The only noticeable difference is that I’m setting the height, when creating the layout parameters, to scale to fit the natural size of the TextView. (Much more on dynamic heights and widths soon.) Once I’ve told the TextView how it will be positioned in its parent layout via the layout parameters, I tell it which string I’d like to display. This string is defined in /res/values/strings.xml. The name attribute in XML determines what needs THE VIEW CLASS 57 to appear after R.string for the system to locate your resource. You’ll learn much more about resource management in the next section. Last, I need to add the new TextView into the LinearLayout and then return the LinearLayout so it can be set as the main content view for the activity. Once that’s finished, I have a layout constructed at runtime with Java code, which identically matches the layout provided by the system in XML form. The Java code looks fairly straightforward, but XML is a much better idea for working with the layout. Using XML, you can use Android’s resource management system and give non-software engineers the ability to modify the application UI. ALTERING THE UI AT RUNTIME It’s one thing to use XML or Java to define the pile of views that compose your user interface. But particularly in the XML case, you’ll want to be able to retrieve and alter views with data acquired over the network, from the user, or from any other information source. Android provides a simple method for gaining access to the views that currently compose your screens by calling findViewById, which is an Activity class method. IDENTIFYING YOUR VIEWS Before you can find one of your views at runtime, you’ll need to give it an ID. Once you’ve called setContentView on an activity, you can call findViewById to retrieve your views and then alter them. This process should look at least a little bit familiar, because you saw it in the previous chapter. Here’s what it looks like in XML: 58 CHAPTER 3 CREATING USER INTERFACES In this case, I’ve added an android:id line to name the TextView. The @+ notation tells Android that rather than referring to a view, you’d like to create an ID for the view. The first reference to any ID must start with @+id. Subsequent references to that ID will start simply with @id. Android keeps its own reserved IDs name-space. For example, if you’re creat- ing a layout to be used by ListActivity (an activity specifically designed to show lists of information), you’ll want to set the ID on your main onscreen ListView to “android:id=”@id/android:list”. These well-known IDs allow Android’s system code to correctly find and interact with the list view that you specify. I’ll provide you with more on this subject in Chapter 5, which covers list creation and management. If you’re creating a view at runtime, simply call setId and pass in an integer, and you’ll be able to retrieve it later. FINDING YOUR RESOURCES WITH ANDROID When Android compiles your project, it assigns a number value for your new static numeric ID. It places this new ID in the R.java file within your project. This file is your gateway to everything you’ve defined inside the res folder. For every layout, drawable, and identified view—and for a host of other things—Android places a subsequent statically defined int into the R file that identifies those things. Anytime you add a line to your layout XML defining a new ID (for example, android:id=”@+id/my_new_id”), you’ll find that after the next time you compile your project, you’ll have an entry in the R.id class. In the previous example, this entry would be R.id.my_new_id. RETRIEVING A VIEW Getting the existing instance of an Android view is as simple as calling findViewById and passing in the ID value found in the R.java file. Given the earlier XML example, here’s how you would grab an instance of the text view and modify its contents. public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); TextView tv = (TextView)findViewById(R.id.text_holder); if(tv!=null) tv.setText(R.string.hello); } THE VIEW CLASS 59 If you are reading this book in order, this should look eerily familiar. I’m retriev- ing an instance of the text view as described by the layout XML. Remember that calling findViewById only works after you’ve called setContentView within the onCreate method. Also, it’s always a good idea to check for null to make sure the system was able to retrieve what you’re looking for. Later layouts for different screen configurations may not have all the views your current layout does. Think of it as future-proofing your UI code for different landscape layouts. KEEPING YOUR VIEWS AROUND Calling findViewById will return an object that persists for the duration of your activity. This means you can add private data members to your Activity class to reduce the number of times you need to reach into the view hierarchy and find them. If you modify a view only once or twice during the lifetime of your activity, this trick won’t save you much time, but it can save significant time if you’re mak- ing frequent updates to multiple views on a very complex screen. It’s a very bad idea, however, to keep your views hanging around once your activity’s onDestroy method has been invoked by the system. Making changes to a view that was once part of an expired activity will have dire consequences (force close dialogs, grumpy users, bad market reviews). XML VS. JAVA LAYOUTS On the whole, laying out your view in Java is nearly as simple as writing it out in XML. So, why would you put any layouts in XML? The short answer is that Android has systems in place to load different XML layouts for you depending on the deployment device screen size and configuration. Do all this work in Java and you won’t be able to take advantage of this massive time saver. Also, it takes a programmer to modify Java code, but most designers can beat the XML layouts into displayable shape. Although you might be the only one working on your current project, this will not be true for all your projects. The longer answer to the question of XML versus Java layouts will become clear as you read the “Resource Management” section. 60 CHAPTER 3 CREATING USER INTERFACES HANDLING A FEW COMMON TASKS Some tasks are more common than others. Let’s take a look at how you can handle some of the ones that you’ll do a few dozen times before you finish your first application. CHANGING THE VISIBILITY OF A VIEW Most of the time, if you want to define your UI in XML you’ll need to add views that will be visible only some of the time. Depending on how dynamic your application is, views come and go fairly regu- larly. Showing and hiding views is as simple as using the ever trusty findViewById and then calling setVisibility on the returned object: Button button = (Button)findViewById(R.id.sample_button); //Cycle through the View Visibility settings if(button != null){ //Gone (no impact on layouts) button.setVisibility(View.GONE); //Invisible (holds its space in a layout but is not drawn) button.setVsibility(View.INVISIBLE); //Visible (duh) button.setVisibility(View.VISIBLE); } This code has three visibility settings. GONE and VISIBLE are the most obvious. You’ll find yourself using INVISIBLE less often, however it’s great for keeping all the other views inside your layouts from moving around when you want to hide something. TIP: If you find yourself doing this a lot, be sure to check out the ViewStub class. THE VIEW CLASS 61 SETTING AN ONCLICKLISTENER Setting up a listener to tell you that one of your views has been clicked is one of the most common tasks you’ll do when working on an Android application. A click can mean the user moved focus to your view using the navigation pad or trackball and then clicked the select key. A click can also mean pressing on the trackball, if there’s one of those, or on the key in the center of the four- or eight-way directional pad. Your click listener will also be called if, in touch mode, the user taps their finger down on your view and then lifts up with their finger still within the bounds of the view. This is an important distinction, as your click listener will not be invoked when their finger actually clicks down on the view but rather when the user lifts their finger up. This gives the user the chance to put a finger down in the wrong place and then correct the position before lifting it. You can track view clicks in several ways. You can declare that your activity itself implements the view’s OnClickListener interface, add a public void onClick (View v) method, and pass a pointer to your activity to the view you wish to track. Here’s what that looks like in code for theoretical buttons with IDs button_one and button_two declared in an imaginary main.xml layout file: public class UiDemoActivity extends Activity implements p OnClickListener { @Override public void onClick(View selectedView) { if(selectedView.getId() == R.id.button_one){ //Take Button One actions } if(selectedView.getId() == R.id.button_one){ //Take Button Two actions } } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); 62 CHAPTER 3 CREATING USER INTERFACES Button button = (Button)findViewById(R.id.button_one); if(button != null) button.setOnClickListener(this); Button button_two = (Button)findViewById(R.id.button_two); if(button_two!= null) button_two.setOnClickListener(this); } There are two methods at work here. In the onCreate method that is called when the activity is being initialized, you’ll see me pulling button_one and button_two out of the layout with findViewById. If the system correctly returned an instance, I register my activity (passing in a pointer to the activity with “this”) as the click listener for each view. Registering a click listener with a view does two things. First, it tells the system to call the appropriate onClick method. Second, it tells the system that this view accepts both focus (highlightable by the navigation buttons) and touch events. You can switch these states on or off by yourself with code, but setting a click listener ensures that click events can actually be heard by the view. There’s a second way to set up the same dynamic. This method sets up a new OnClickListener object for each view. This can help keep code separate if your screen has a lot of clickable items on it. Here’s what this pattern looks like, and it achieves the same results as the previous code. public class UiDemoActivity extends Activity{ private View.OnClickListener mClickListenerOne = new View.OnClickListener() { @Override public void onClick(View v) { //Do button one stuff here } }; private View.OnClickListener mClickListenerTwo = THE VIEW CLASS 63 new View.OnClickListener() { @Override public void onClick(View v) { //Do button two stuff here } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Button button = (Button)findViewById(R.id.button_one); if(button != null) button.setOnClickListener(mClickListenerOne); Button button_two = (Button)findViewById(R.id.button_two); if(button_two!= null) button_two.setOnClickListener(mClickListenerTwo); } } This time, instead of declaring my activity as an implementer of the OnClick Listener, I’m creating two separate inner objects to handle the click event from each individual button. I’ll put the code required for button_one in the first object and the code for button_two in the second. I do this frequently in my own appli- cations when I have several buttons on the screen. It keeps me from having one heaping pile of if statements (or one switch statement) that figure out which view was clicked and then take the appropriate action. Depending on your needs, you can mix and match two techniques. There isn’t a huge advantage either way, but it’s good to know each so you can keep your code in good order. 64 CHAPTER 3 CREATING USER INTERFACES In this example, I’ve added a click listener to two buttons. A click listener can be attached to any view that you want users to interact with. This can be anything from entire view groups to simple text views. It’s worth mentioning again that by setting a click listener, you’re telling the system that the item can be selected (touched with a finger) and clicked (highlighted with the trackpad and then clicked with the center key or trackball). As a result, whatever default selection action is configured for the view will automatically run on a select event (either from the directional keypad or the touchscreen). Buttons, for example, change colors when a user selects them. Text views, depending on the device’s default UI style, may also change the active color of the text. In the end, you can (and probably should) specify custom display behavior by declaring a state-full drawable. I’ll show you how to do such things later in the book. CREATING CUSTOM VIEWS The concept of custom views can really be broken out into two sections: extending an existing view and creating an entirely new one. I’ve rarely, in my career as an Android developer, created a completely custom view, so we’ll skip over it here. The Android SDK documentation has directions for the industrious among you who want to roll your very own from scratch. However, even if you plan to extend an Android view, you must create a new class that extends the existing view. Here’s how you’d go about it. DECLARING THE NEW CLASS The first step in declaring a custom view is to create the class. Android allows you to subclass any of its existing UI objects simply by extending an existing class. The declaration looks like this: public class CustomTextView extends TextView{ public CustomTextView(Context context) { super(context); } } THE VIEW CLASS 65 That’s all it takes to create a custom text view. However, since there’s about as much custom in this custom text view as there is beef in fast-food tacos, I’ll add something simple to set it apart. EXTENDING A VIEW Although Android’s layouts and views are powerful and versatile, there are times when they just won’t do exactly what you want. Fortunately, their functionality is easy to extend. To demonstrate, I’ve written a custom text view that changes the color of every letter in the text to be displayed onscreen. While this isn’t the most practical use case, it will show how simple it is to implement your own behavior. CUSTOMIZING AN EXTENDED VIEW You’d be amazed at how much code it takes to correctly render text to the screen. Android’s TextView.java class is nearly 5000 lines of code. But thanks to the ability to extend a class, you can use all the complex layout code and customize only the part that appeals to you. In this example, I catch the text as it changes and add a new ForegroundColorSpan for each letter in the new string. First, I declare an array of colors. public class CustomTextView extends TextView{ int colorArray[] = new int[]{Color.WHITE, Color.RED, Color.YELLOW, Color.GREEN, Color.BLUE, Color.MAGENTA, Color.CYAN, Color.DKGRAY}; 66 CHAPTER 3 CREATING USER INTERFACES Now, each time the text changes, I add a new ForegroundColorSpan for each letter. protected void onTextChanged(CharSequence text, int start, int before, int after ) { //Keep the view from getting into an infinite loop if(selfChange){ selfChange = false; return; } selfChange=true; } I make sure I don’t get stuck in an infinite loop (with the change in color trig- gering another onTextChanged call, which changes the color again, which changes the color . . . you get the idea). Next comes the code that changes the colors: SpannableStringBuilder builder = new SpannableStringBuilder(text); builder.clearSpans(); ForegroundColorSpan colorSpan; int color; for(int i=0; i < text.length(); i++){ //pick the next color color = colorArray[i%colorArray.length]; //Create the color span colorSpan = new ForegroundColorSpan(color); //Add the color span for this one char builder.setSpan(colorSpan, i, i, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } setText(builder); THE VIEW CLASS 67 Again, not very complex, but then neither is extending an existing view class. Also, be warned that this code will clear any formatting that may have already been set on the text. (At this point, don’t stress too much about how spans and SpannableStringBuilders work. In short, they’re blocks of formatting that you can drop over strings. Check the Android SDK documentation for more info.) If you’re looking for a coding challenge, try creating an array with every possible RGB hex color value and cycling through that array. USING YOUR EXTENDED VIEW Just as with any other Android view, you can create a new instance of it at runtime in your Java code or pre-declare it in your XML layout file. Here’s how you can use it in your activity: public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); CustomTextView customView = new CustomTextView(this); customView.setText(“Hello There!”); setContentView(customView); } There’s nothing you haven’t seen before going on here. I’m creating a new instance of my view, setting the text for it, and then setting it as the main view for my activity. You could also put it inside a layout object with other views. It’s also possible to add this custom view to an XML-described layout. But before you can start declaring your custom view in an XML file, you need to create the full suite of View constructors. Your custom view should look something like this: public class CustomTextView extends TextView{ public CustomTextView(Context context, AttributeSet attributeSet, int defSytle) { super(context, attributeSet, defSytle); } 68 CHAPTER 3 CREATING USER INTERFACES public CustomTextView(Context context, AttributeSet attributeSet) { super(context, attributeSet); } public CustomTextView(Context context){ super(context); } //Rest of the class omitted for brevity } When Android parses your XML layout and creates your view, it needs to pass an attribute set to the constructor because this contains all the layout informa- tion, text, and whatever else you’ve added that starts with android. If you forget to add these, everything will compile, but it will show the Unexpected Force Close window of doom when you try to draw the screen. Now that you have the correct constructors, it’s possible to create and lay out your custom view within XML. In the code to follow, I’ve added a single instance of the rainbow animating custom text display. THE VIEW CLASS 69 As you can see, adding a custom text view to your XML layouts only requires you to use the full Java package and class name. You can also see that because CustomTextView extends TextView, I can use any attribute (like android:text) that I would use with one of Android’s TextViews. Congrats, you’ve created a custom Android view to do your bidding in only a few lines of code, you’ve displayed it to the screen, and you even have the capability to include it within a more complex layout system. Google has done a fantastic job of allowing developers to extend the functionality of basic building blocks included in the Android SDK. If this extended custom view leaves you wanting more of a challenge, try making a simple text view that does exactly the same things as the extended view. You’ll need to explore the onMeasure and onDraw methods of your own view. Go ahead, check it out, I’ll be here when you get back. 70 CHAPTER 3 CREATING USER INTERFACES RESOURCE MANAGEMENT Android has many tools to help you manage string literals, images, layouts, and more. Moving all this constant data into external files makes life as a programmer easier in a multitude of ways. In previous code examples, I’ve referenced the R.java file when specifying strings, drawable images, and layouts and mentioned that an explanation would be forthcoming. Now is the time to explain Android resource management in detail. RESOURCE FOLDER OVERVIEW Every Android project, by default, contains a res folder with several subfolders inside it. Each subfolder is responsible for a different aspect of your application’s data. The drawable folders (drawable-hdpi, drawable-mdpi, and drawable-ldpi) hold images and XML files describing drawable objects. You’ll learn much more about what you can do with drawable objects in later chapters. The values folder holds all your textual content, from string literals to menu list value arrays to color constants. Lastly, the layout folders contain XML files to describe how you want your screens to look. At compile time, the Android tools take all the folders in your res directory and place a corresponding ID into an R.java file. This file is automatically re-created and placed in the project’s gen folder. Consequently, you should never directly change this R.java file, because any changes are removed the next time you compile. The IDs in R.java can be passed to everything from XML parsers to text and image views. When you call setText on a TextView and pass in R.string.hello, the view then knows to look for that ID in the string file and display what it finds there. When you set the main view of an activity by calling setContentView and passing in R.layout .main, the system knows it needs to inflate and create the views found in res/layout/ main.xml and add them to the active views on the screen for the current activity. RESOURCE MANAGEMENT 71 Here’s what the R.java file looks like for a newly created project: /* AUTO-GENERATED FILE. DO NOT MODIFY. * * This class was automatically generated by the * aapt tool from the resource data it found. It * should not be modified by hand. */ package com.haseman.peachpit; public final class R { public static final class attr { } public static final class drawable { public static final int icon=0x7f020000; } public static final class layout { public static final int main=0x7f030000; } public static final class string { public static final int app_name=0x7f040001; public static final int hello=0x7f040000; } } 72 CHAPTER 3 CREATING USER INTERFACES When Android compiles your XML files, it renders them to a packed binary format. The upside of this format is that it loads much faster, so your screens can snap into focus more quickly. The downside is that you cannot modify any of these files once they’ve been compiled. So you can’t manipulate your layout and string files at runtime. You can, however, modify what is rendered to the screen by loading and changing strings in the Java representation of the views. Additionally, if you want to reference various resources from other XML files, you’ll use the @folder/object_id structure. While you may not have been aware of it, you’ve seen this kind of declaration in action already. Think back to the ini- tial Hello World layout that the Android tools provide for you. In it, you saw a text view with the following line: android:text=”@string/hello”. This was Android’s resource system at work. Instead of specifying R.string.hello, you’ll use the XML’s @string/hello for XML. Each type of folder (drawable, layout, values, and several more) has special naming conventions and tricks you can use to battle the time-consuming problems of device diversity, language localization, and differing screen resolutions and densities. Let’s look at what you can do with each type of file. VALUES FOLDER The prospect of putting all the constant values for your user interface (strings, colors, or int/string arrays) in a separate file might sound annoying at first (especially when you consider that all text manipulators will take a resource ID or a CharSequence). However, it can cut down many days of work when translating your application to different languages. Having all your strings in an external XML file also means that your nontech- nical colleagues (product managers, designers, or micromanaging bosses) can manipulate the display text in the screens, menus, and pop-up dialogs without bothering you. This assumes, of course, that you teach them how to compile and run the project; feel free to share the first chapter of this book with them. The values folder can contain: Strings. All string literals should go into your strings.xml file. Arrays. There is a file for the XML-defined arrays, but string arrays can still go in the strings.xml file if you don’t feel like using a separate file. RESOURCE MANAGEMENT 73 Colors. colors.xml can contain any number of declared color constants for use in everything from text fonts to layout backgrounds. Unless you’re planning on doing a lot of custom UI drawing, this file will probably not be very large. Dimensions. dimens.xml can contain any number of possible size values used elsewhere in your layouts. This file is particularly handy if you wish to make a view taller or shorter based on the display size of the device your application is being displayed on. This might seem like a simple thing to do, but it can be very powerful when combined with the layout folders. Styles. styles.xml . . . yeah . . . more about this later. You can create new values folders for each language by using the two-letter ISO639-2 suffix for a particular language as a suffix to values. You can, for example, create a values-es folder containing a Spanish version of the strings.xml file. When a user sets his or her phone to Spanish, Android will check automatically for an R.string.hello value defined in the strings.xml file within the new values-es folder. If it finds one, it will display the values-es version rather than the default. If it doesn’t find a Spanish translation, it will default to the value you defined in values/strings.xml. In this way, Android provides you with an easy way to localize all the strings in your application. It does, however, require you to be vigilant about placing your string literals in the strings.xml file rather than just calling setText(“Text like this”); or using android:text=”Text like this” in your XML. LAYOUT FOLDERS I’m going to give you three guesses as to what exactly goes into the layout folders. Typically, it’s where you place either layout XML files for use in setContentView calls, or sub-layouts that can be included via ViewStubs or inherited views (two tools that allow you to reuse views in different layouts). Android builds a helpful mechanic into the layout folders. You can have many folders, with different suf- fixes, that describe how you want the application to appear under various screen configurations. 74 CHAPTER 3 CREATING USER INTERFACES The simplest example is a layout folder and a layout-land folder. If you place a firstscreen.xml file in both folders, Android will use the one that most closely resembles the current screen mode. If you keep the android:id settings consistent, you will be able to specify two completely different-looking screens within your XML markups and interact with any of them via your Java code. This technique is complicated, so let’s look at an example. Let’s say you create portrait and landscape layouts for the first screen of your application. Both files are called firstscreen.xml, and the portrait version goes in the layout folder while the landscape version goes in the layout-land folder. You could also put the portrait version in a folder called layout-port. In both ver- sions of firstscreen.xml, you provide all the appropriate IDs for the text views, buttons, and images. If your screen had an OK button, you’d provide the portrait and landscape versions of these buttons the same ID: R.id.ok_button. Remember that you gain access to views by calling findViewById() and passing in the ID you specified on the android:id=”@+id/id_goes_here” line. In this case, if you wanted to set a click listener, you’d fetch the OK button by calling findViewById(R.id.ok_button); and Android would return the button from your portrait screen if you’re in portrait mode and the landscape version of the button if you’re in landscape mode. Your code knows what it must do when that button is pressed, but it doesn’t know about the dimensions or location of the button. Welcome to the happy land of the Model- View-Controller (MVC). MVC is your number one friend when handling the diversity in device screen sizes. You can lay out your views in any possible configuration and, as long as the IDs match, you’ll need to write only a single Activity class to handle all possible screen permutations. You can have specific folders, each with its own set of layout files for different screen sizes (layout-small to layout-xlarge) and densities (layout- ldpi to layout-hdpi), and you can mix and match. For example, layout-large-land would specify layouts for large screens (VGA and WVGA) that are in landscape mode. For the exact order in which Android defaults through the folders, be sure to check the Android SDK documentation. I’m only scratching the surface of the possibilities that these layout folders put at your disposal. You’ll learn more about this topic in coming chapters on dealing with display and hardware diversity. RESOURCE MANAGEMENT 75 DRAWABLE FOLDERS For Android, a drawable is simply something that can be drawn to the screen. Android abstracts away the differences between colors, shapes, and images and allows you to deal with a superclass that can represent any number of them: Drawable. You keep the definitions for these objects in the drawable folders. You should consider using a drawable for two main types of objects: ᭿ Image resources (mostly PNG files) ᭿ XML files describing things you want drawn: shapes, gradients, or colors The drawable set of folders works similarly to the layout folders. You can specify any mix of screen densities, layouts, or resolutions, provided you specify them in the right order. MANY RESOURCES, ONE APK Just because you can have a whole different set of images for each screen size or density doesn’t mean you actually should. Keep a close eye on the size of your final compiled APK file. If the file grows over a certain size, users will complain. To combat this bloat, use 9-patches, which are easily scaled images, and use hand-rendered shapes over large PNG graphics where pos- sible. While the new marketplace does allow for multiple APKs, it’s a level of complexity you should avoid. Referencing a drawable is accomplished in the same way that you reference values and layouts. For XML files, use the @drawable/resource_name. For example, in an ImageView (android:src=”@drawable/bridge”), omit the suffix if you’re referring to XML files or images. Also, keep in mind that Android will always try to use the drawable folder that is closest to your current configuration. If it can’t find a good match, it’ll cascade back to what it can find in the default drawable folder. TIP: Be sure to check the Android SDK documentation for more info on ordering your suffixes correctly. 76 CHAPTER 3 CREATING USER INTERFACES LAYOUT MANAGEMENT Layouts, from the simple to the complex, describe how to arrange a complex series of views. This section covers the basics of Android’s arsenal of layout classes start- ing with the ViewGroup, moving through LinearLayouts, and ending with the king of the Android screen arrangers, the RelativeLayout. THE VIEWGROUP Each layout in Android extends what’s known as the ViewGroup. This is the class of views that by definition can contain other views as children. To demonstrate how each of the major layouts function, I’ll be laying out an example picture-viewer screen. While Android provides its own snazzy photo viewer, complete with a thumbnail carousel, mine will be simple and an excellent vehicle for showing you how the various layouts work. Figure 3.1 shows the screen that we’ll be rendering using the AbsoluteLayout, the LinearLayout, and the RelativeLayout. FIGURE 3.1 A taste of what’s to come. LAYOUT MANAGEMENT 77 The example picture viewer has two sections: the button bar with title and the image itself. The button bar contains Next and Prev buttons and a text view displaying the name of the image. Before getting too deep into the layout, there are a few terms to watch for in the XML: dip or dp. This is how Android helps you scale your screen layout to devices with different pixel densities. For example, on the Nexus S screen, 1dp = 1.5 pixels. It can be annoying to constantly convert the locations onscreen to dips, but this small investment in time will pay huge divi- dends when you’re running on a multitude of Android screens. Example: android:padding=”20dp”. px. Use this suffix to define an absolute pixel value for the specified dimen- sion. In most cases, you should avoid declaring the absolute pixel value and use dp. Example: android:paddingLeft=”15px”. match_parent and wrap_content. Before you can draw an Android view to the screen, it must have a defined width and height. You can define either of these two values as a constant value (20dp), or you can use one of the two special height and width values, fill_parent or wrap_content. Each value does exactly what you’d expect. fill_parent will make the view attempt to match the dimension of its parent. wrap_content will first request the measured size of the view and then attempt to set that dimension as the layout width for the view itself. With a few simple definitions out of the way, I can start in on the various layout classes. I’ll start with one that you’ll find appealing but that you should never use in practice. THE ABSOLUTELAYOUT The most important thing you should know about AbsoluteLayouts is that you should never use them. They are the quintessential beginner’s trap. They appear to be a good idea at first (as they quickly give you exact pixel design), but they can be frustrating, require excess time laying out new screens, and cause frequent face-desk interaction. Consult your local Android expert if you experience any of 78 CHAPTER 3 CREATING USER INTERFACES these side effects while trying to use an AbsoluteLayout. They’ll likely try to talk you out of this lunacy. The AbsoluteLayout, as you might have guessed, allows you to specify exactly where on the screen you want a particular view to go. Each child of an AbsoluteLayout should have android:layout_x and android:layout_y values along with the required width and height settings. You are probably thinking, “That sounds like a great way to make layouts look exactly the way I want them to. Why bother learning anything else when I can take my screen designs and convert them directly into pixel x/y locations?” I thought the same thing . . . at first. Here’s what the AbsoluteLayout layout XML looks like:
还剩272页未读

继续阅读

下载pdf到电脑,查找使用更方便

pdf的实际排版效果,会与网站的显示效果略有不同!!

需要 8 金币 [ 分享pdf获得金币 ] 2 人已下载

下载pdf

pdf贡献者

sunlinxin

贡献于2013-01-15

下载需要 8 金币 [金币充值 ]
亲,您也可以通过 分享原创pdf 来获得金币奖励!
下载pdf