|
Cyril Sermon (@admin) |
Most of the applications you create in Android will fall into one of the following categories:
❑Foreground Activity An application that’s only useful when it’s in the foreground and is effectively suspended when it’s not visible. Games and map mashups are common examples.
❑Background Service An application with limited interaction that, apart from when being con-figured, spends most of its lifetime hidden. Examples of this include call screening applications or SMS auto-responders.
❑Intermittent Activity Expects some interactivity but does most of its work in the background. Often these applications will be set up and then run silently, notifying users when appropriate. A common example would be a media player.
Complex applications are difficult to pigeonhole into a single category and include elements of all three. When creating your application, you need to consider how it’s likely to be used and then design it accordingly. Let’s look more closely at some of the design considerations for each application type described above.
When creating foreground applications, you need to consider the Activity life cycle (described in Chap-ter 3) carefully so that the Activity switches seamlessly between the foreground and the background.
Applications have no control over their life cycles, and a backgrounded application, with no Services, is a prime candidate for cleanup by Android’s resource management. This means that you need to save the state of the application when the Activity becomes invisible, and present the exact same state when it returns to the foreground. It’s also particularly important for foreground Activities to present a slick and intuitive user experience.
You’ll learn more about creating well-behaved and attractive foreground Activities in Chapter 3.
These applications run silently in the background with very little user input. They often listen for mes-sages or actions caused by the hardware, system, or other applications, rather than rely on user interaction.
It’s possible to create completely invisible services, but in practice, it’s better form to provide at least some sort of user control. At a minimum, you should let users confirm that the service is running and let them configure, pause, or terminate it as needed.
Services, the powerhouse of background applications, are covered in depth in Chapter 8.
Often you’ll want to create an application that reacts to user input but is still useful when it’s not the active foreground Activity. These applications are generally a union of a visible controller Activity with an invisible background Service.
These applications need to be aware of their state when interacting with the user. This might mean updating the Activity UI when it’s visible and sending notifications to keep the user updated when it’s in the background, as seen in the section on Notifications and Services in Chapter 8.
Android does a lot to simplify mobile-device software development, but it’s still important to under-stand the reasons behind the conventions. There are several factors to account for when writing soft-ware for mobile and embedded devices, and when developing for Android, in particular.
In this chapter, you’ll learn some of the techniques and best practices for writing efficient Android code. In later examples, efficiency is sometimes compromised for clarity and brevity when introducing new Android concepts or functionality. In the best traditions of “Do as I say, not as I do,” the examples you’ll see are designed to show the simplest (or easiest-to-understand) way of doing something, not nec-essarily the best way of doing it.
Small and portable, mobile devices offer exciting opportunities for software development. Their limited screen size and reduced memory, storage, and processor power are far less exciting, and instead present some unique challenges.
Compared to desktop or notebook computers, mobile devices have relatively:
❑ Low processing power ❑ Limited RAM
❑Limited permanent storage capacity
❑Small screens with low resolution
❑Higher costs associated with data transfer
❑ Slower data transfer rates with higher latency ❑ Less reliable data connections
❑Limited battery life
It’s important to keep these restrictions in mind when creating new applications.
Manufacturers of embedded devices, particularly mobile devices, value small size and long battery life over potential improvements in processor speed. For developers, that means losing the head start traditionally afforded thanks to Moore’s law. The yearly performance improvements you’ll see in desk-top and server hardware usually translate into smaller, more power-efficient mobiles without much improvement in processor power.
In practice, this means that you always need to optimize your code so that it runs quickly and respon-sively, assuming that hardware improvements over the lifetime of your software are unlikely to do you any favors.
Since code efficiency is a big topic in software engineering, I’m not going to try and capture it here. This chapter covers some Android-specific efficiency tips below, but for now, just note that efficiency is par-ticularly important for resource-constrained environments like mobile devices.
Advances in flash memory and solid-state disks have led to a dramatic increase in mobile-device stor-age capacities (although people’s MP3 collections tend to expand to fill the available space). In practice, most devices still offer relatively limited storage space for your applications. While the compiled size of your application is a consideration, more important is ensuring that your application is polite in its use of system resources.
You should carefully consider how you store your application data. To make life easier, you can use the Android databases and Content Providers to persist, reuse, and share large quantities of data, as described in Chapter 6. For smaller data storage, such as preferences or state settings, Android provides an optimized framework, as described in Chapter 6.
Of course, these mechanisms won’t stop you from writing directly to the filesystem when you want or need to, but in those circumstances, always consider how you’re structuring these files, and ensure that yours is an efficient solution.
Part of being polite is cleaning up after yourself. Techniques like caching are useful for limiting repeti-tive network lookups, but don’t leave files on the filesystem or records in a database when they’re no longer needed.
The small size and portability of mobiles are a challenge for creating good interfaces, particularly when users are demanding an increasingly striking and information-rich graphical user experience.
Write your applications knowing that users will often only glance at the (small) screen. Make your applications intuitive and easy to use by reducing the number of controls and putting the most impor-tant information front and center.
Graphical controls, like the ones you’ll create in Chapter 4, are an excellent way to convey dense infor-mation in an easy-to-understand way. Rather than a screen full of text with lots of buttons and text entry boxes, use colors, shapes, and graphics to display information.
If you’re planning to include touch-screen support (and if you’re not, you should be), you’ll need to con-sider how touch input is going to affect your interface design. The time of the stylus has passed; now it’s all about finger input, so make sure your Views are big enough to support interaction using a finger on the screen. There’s more information on touch-screen interaction in Chapter 11.
Of course, mobile-phone resolutions and screen sizes are increasing, so it’s smart to design for small screens, but also make sure your UIs scale.
In Chapter 5, you’ll learn how to use Internet resources in your applications. The ability to incorporate some of the wealth of online information in your applications is incredibly powerful.
The mobile Web unfortunately isn’t as fast, reliable, or readily available as we’d often like, so when you’re developing your Internet-based applications, it’s best to assume that the network connection will be slow, intermittent, and expensive. With unlimited 3G data plans and city-wide Wi-Fi, this is chang-ing, but designing for the worst case ensures that you always deliver a high-standard user experience.
This also means making sure that your applications can handle losing (or not finding) a data connection.
The Android Emulator lets you control the speed and latency of your network connection when setting up an Eclipse launch configuration. Figure 2-7 shows the emulator’s network connection speed and latency set up to simulate a distinctly suboptimal EDGE connection.
Experiment to ensure responsiveness no matter what the speed, latency, and availability of network access. You might find that in some circumstances, it’s better to limit the functionality of your applica-tion or reduce network lookups to cached bursts, based on the network connection(s) available. Details
on how to detect the kind of network connections available at run time, and their speeds, are included in Chapter 10.
If you’re a mobile owner, you know all too well that some of the more powerful features on your mobile can literally come at a price. Services like SMS, GPS, and data transfer often incur an additional tariff from your service provider.
It’s obvious why it’s important that any costs associated with functionality in your applications are minimized, and that users are aware when an action they perform might result in them being charged.
It’s a good approach to assume that there’s a cost associated with any action involving an interaction with the outside world. Minimize interaction costs by the following:
❑Transferring as little data as possible
❑Caching data and GPS results to eliminate redundant or repetitive lookups
❑Stopping all data transfers and GPS updates when your activity is not visible in the foreground if they’re only being used to update the UI
❑ Keeping the refresh/update rates for data transfers (and location lookups) as low as practicable ❑ Scheduling big updates or transfers at “off peak” times using alarms as shown in Chapter 8
Often the best solution is to use a lower-quality option that comes at a lower cost.
When using the location-based services described in Chapter 7, you can select a location provider based on whether there is an associated cost. Within your location-based applications, consider giving users the choice of lower cost or greater accuracy.
In some circumstances, costs are hard to define, or they’re different for different users. Charges for ser-vices vary between service providers and user plans. While some people will have free unlimited data transfers, others will have free SMS.
Rather than enforcing a particular technique based on which seems cheaper, consider letting your users choose. For example, when downloading data from the Internet, you could ask users if they want to use any network available or limit their transfers to only when they’re connected via Wi-Fi.
You can’t assume that your users will think of your application as the most important feature of their phones.
Generally, a mobile is first and foremost a phone, secondly an SMS and e-mail communicator, thirdly a camera, and fourthly an MP3 player. The applications you write will most likely be in a fifth category of “useful mobile tools.”
That’s not a bad thing — it’s in good company with others including Google Maps and the web browser. That said, each user’s usage model will be different; some people will never use their mobiles.
❑Is polite Your application should never steal focus or interrupt a user’s current activity. Use Notifications and Toasts (detailed in Chapter 8) instead to inform or remind users that their attention is requested if your application isn’t in the foreground. There are several ways for mobile devices to alert users. For example, when a call is coming in, your phone rings; when you have unread messages, the LED flashes; and when you have new voice mail, a small “mail” icon appears in your status bar. All these techniques and more are available through the notifi-cation mechanism.
❑Presents a consistent user interface Your application is likely to be one of several in use at any time, so it’s important that the UI you present is easy to use. Don’t force users to interpret and relearn your application every time they load it. Using it should be simple, easy, and obvi-ous — particularly given the limited screen space and distracting user environment.
❑Is responsive Responsiveness is one of the most important design considerations on a mobile device. You’ve no doubt experienced the frustration of a “frozen” piece of software; the mul-tifunction nature of a mobile makes it even more annoying. With possible delays due to slow and unreliable data connections, it’s important that your application use worker threads and background services to keep your activities responsive and, more importantly, stop them from preventing other applications from responding in a timely manner.
Nothing covered so far is specific to Android; the design considerations above are just as important when developing applications for any mobile. In addition to these general guidelines, Android has some particular considerations.
To start with, it’s worth taking a few minutes to read Google’s Android design philosophy at http://code.google.com/android/toolbox/philosophy.html.
The Android design philosophy demands that applications be:
❑Fast
❑ Responsive ❑ Secure
❑Seamless
In a resource-constrained environment, being fast means being efficient. A lot of what you already know about writing efficient code will be just as effective in Android, but the limitations of embedded systems and the use of the Dalvik VM mean you can’t take things for granted.
The smart bet for advice is to go to the source. The Android team has published some specific guidance on writing efficient code for Android, so rather than rehash their advice, I suggest you visit http:// code.google.com/android/toolbox/performance.html and take note of their suggestions.
You may find that some of these performance suggestions contradict established design practices — for example, avoiding the use of internal setters and getters or preferring virtual over interface. When writing software for resource-constrained systems like embedded devices, there’s often a compromise between conventional design principles and the demand for greater efficiency.
One of the keys to writing efficient Android code is to not carry over assumptions from desktop and server environments to embedded devices.
At a time when 2 to 4 GB of memory is standard for most desktop and server rigs, even advanced smartphones are lucky to feature 32 MB of RAM. With memory such a scarce commodity, you need to take special care to use it efficiently. This means thinking about how you use the stack and heap, limit-ing object creation, and being aware of how variable scope affects memory use.
Android takes responsiveness very seriously.
Android enforces responsiveness with the Activity Manager and Window Manager. If either service detects an unresponsive application, it will display the unambiguous Application unresponsive (AUR) message, as shown in Figure 2-8.
This alert is modal, steals focus, and won’t go away until you hit a button or your application starts responding — it’s pretty much the last thing you ever want to confront a user with.
Android monitors two conditions to determine responsiveness:
❑An application must respond to any user action, such as a key press or screen touch, within 5 seconds.
❑A Broadcast Receiver must return from its onReceive handler within 10 seconds.
The most likely culprits for causing unresponsiveness are network lookups, complex processing (such as calculating game moves), and file I/O. There are a number of ways to ensure that these actions don’t exceed the responsiveness conditions, in particular, using services and worker threads, as shown in Chapter 8.
The AUR dialog is a last resort of usability; the generous 5-second limit is a worst-case scenario, not a benchmark to aim for. Users will notice a regular pause of anything more than half a second between key press and action. Happily, a side effect of the efficient code you’re already writing will be faster, more responsive applications.