• 沒有找到結果。

A Real-World Example

在文檔中 Learning Android (頁 81-88)

In this book, we’re going to build an app to use Twitter. We know that the user should be able to post status updates. We also know the user should be able to see what her friends are up to. Those are basic features. Beyond that, the user should also be able to update her username and password for the online account. So now we know we should have the following three screens: a screen for users to update their own status, a screen to see the status timelines of their friends, and a screen to set the preferences for the app.

Next, we would like this app to work quickly regardless of the network connection or lack thereof. To achieve that, the app has to pull the data from the cloud when it’s online

63

and cache the data locally. That will require a service that runs in the background as well as a database.

We also know that we’d like this background service to be started when the device is initially turned on, so by the time the user first uses the app, there’s already up-to-date information in the local cache.

Finally, we will want to display the latest status from the friends’ timelines on the home screen, as an Android Widget.

These are some straightforward requirements. Android building blocks make it easy to break them down into conceptual units so that you can work on them independently, and then easily put them together into a complete package.

As you’ll see later, these building blocks make up an application. Essentially, an app is not much more than a loose collection of activities, services, providers, and receivers.

Activities

An activity is usually a single screen that the user sees on the device at one time. An application typically has multiple activities, and the user flips back and forth among them. As such, activities are the most visible part of your application.

We usually use a website as an analogy for activities. Just as a website consists of multiple pages, so does an Android application consist of multiple activities. Just as a website has a “home page,” an Android app has a “main” activity, usually the one that is shown first when you launch the application. And just as a website has to provide some sort of navigation among various pages, an Android app should do the same.

On the Web, you can jump from a page on one website to a page on another. Similarly, in Android, you could be looking at an activity of one application, but shortly afterward you could start another activity in a completely separate application. For example, if you are in your Contacts app and you choose to text a friend, you’d be launching the activity to compose a text message in the Messaging application.

Activity Life Cycle

Launching an activity can be quite expensive. It may involve creating a new Linux pro‐

cess, allocating memory for all the UI objects, inflating all the objects from XML layouts, and setting up the whole screen. Because the operating system is doing a lot of work to launch an activity, it would be a waste to just toss it out once the user leaves that screen.

To avoid this waste, the activity life cycle is managed by the Activity Manager, a service that runs inside the Android Framework layer of the stack.

The Activity Manager is responsible for creating, destroying, and managing activities.

For example, when the user starts an application for the first time, the Activity Manager

will create its activity and put it onto the screen. Later, when the user switches screens, the Activity Manager will move that previous activity to a holding place. This way, if the user wants to go back to an older activity, it can be started more quickly. Older activities that the user hasn’t used in a while will be destroyed in order to free more space for the currently active one. This mechanism is designed to help improve the speed of the user interface and thus improve the overall user experience.

Programming for Android is conceptually different from programming for some other environments. In Android, you find yourself responding to certain changes in the state of your application rather than driving that change yourself. It is a managed, container-based environment similar to programming for Java applets or servlets. So, when it comes to an activity life cycle, you don’t get to say what state the activity is in, but you have plenty of opportunity to say what happens during the transitions from state to state. Figure 5-1 shows the states that an activity can go through. The following sections describe how to handle each state.

Figure 5-1. Activity life cycle Starting state

When an activity doesn’t exist in memory, it is in a starting state. As it starts, the activity invokes a set of callback methods that you as a developer have an opportunity to fill out.

These callbacks include onCreate(), onStart(), and onResume(). Eventually, the

Activities | 65

activity will be in a running state, which means that it will be fully displayed on the screen, in focus, waiting for user to interact with it.

Keep in mind that this transition from starting state to running state is one of the most expensive operations the application will perform in terms of computing time, and this also directly affects the battery life of the device. This is the exact reason we don’t au‐

tomatically destroy activities that are no longer shown. The user might want to come back to them, so the operating system, via Activity Manager, keeps them around for some time.

Running state

Only one activity on a device can be in a running state: it’s the one that is currently on the screen and interacting with the user. We also say this activity is in focus, meaning that all user interactions—such as typing, touching the screen, and clicking buttons—

are handled by this one activity.

The running activity has priority in terms of getting the memory and resources it needs to run as quickly as possible. This is because Android wants to make sure the running activity is zippy and responsive to the user.

Paused state

When an activity is not in focus (i.e., not interacting with the user) but still visible on the screen, we say it’s in a paused state. This is not a typical scenario, because the device’s screen is usually small, and an activity is either taking up the whole screen or none at all. We often see this case with dialog boxes that come up in front of an activity, causing it to become paused. All activities go through a paused state en route to being stopped.

Paused activities still have high priority in terms of getting memory and other resources.

This is because they are visible and cannot be removed from the screen without making it look very strange to the user. The Activity Manager calls onPause() when putting your application into the paused state, but we don’t use that hook to perform any ac‐

tivities in this book.

Stopped state

When an activity is not visible, but still in memory, we say it’s in a stopped state. A stopped activity could be brought back to the front to become a running activity again.

Or, it could be destroyed and removed from memory, which is an operating system choice beyond your control.

The system keeps activities around in a stopped state because it is likely that the user will still want to get back to those activities some time soon, and restarting a stopped activity is far cheaper than starting an activity from scratch. That is because the Activity

Manager already has all the objects loaded in memory and simply has to bring them all up to the foreground.

Stopped activities can be removed from memory at any point. It is up to Activity Man‐

ager’s discretion to do so. The Activity Manager calls onStop() when putting your ap‐

plication into this state, so it is wise in this method to do anything you need in order to save the state of your app, such as writing data to disk or a database.

Destroyed state

A destroyed activity is no longer in memory. The Activity Manager decided that this activity is no longer needed and has removed it. Before the activity is destroyed, it can perform certain actions, such as save any unsaved information. However, there’s no guarantee that your activity will be destroyed from the destroyed state. It is possible for a stopped activity to be destroyed as well. For that reason, it is better to do important work, such as saving unsaved data, in the onStop() rather than the onDestroy() callback.

The fact that an activity is in a running state doesn’t mean it’s doing much. It could be just sitting there and waiting for user input. Simi‐

larly, an activity in a stopped state is not necessarily doing nothing.

The state names mostly refer to how active the activity is with re‐

spect to user input; in other words, whether an activity is visible, in focus, or not visible at all.

Why is the process of managing the activity life cycle so complex? On a typical desktop PC, when you are done with an application, such as Microsoft Word or Excel, you close it. Essentially, what you as a user are doing is memory managing your PC. Android’s team felt that users shouldn’t have to manage memory and have delegated that responsi‐

bility to the Activity Manager. Sure, humans would likely do a bet‐

ter job of quitting apps they no longer need, but the automatic way is good enough and makes the overall experience better for the user. We sometimes compare Activity Manager to automatic transmission on a car, or garbage collection in languages such as Java. Yes, humans do a better job with switching manual gears or allocating and freeing memory manually, but that’s just extra work that, in today’s day and age, machines do well enough.

Because the user interface is a big part of most Android apps, we’ll explore how to create activities in detail in Chapter 7.

Activities | 67

There are currently two ways to create activity user interfaces: the standard and older activity views and the newer fragments. Frag‐

ments were introduced in Android version 3.0 as a means to simpli‐

fy the handling of different screen sizes and devices. We will explore this in Chapter 8.

Intents

Intents are messages that are sent among the major building blocks. They trigger an activity to start up, tell a service to start, stop, or bind to, or are simply broadcasts. Intents are asynchronous, meaning the code that sends them doesn’t have to wait for them to be completed. To use our analogy with a website, intents would be the links connecting various pages together. Just like a web link, an intent can be internal to a single app or, just as easily, connect to components in other apps. And just like links, intents can carry small amounts of primitive data with them.

An intent could be explicit or implicit. In an explicit intent, the sender clearly spells out which specific component should be on the receiving end. In an implicit intent, the sender specifies just the type of receiver. For example, your activity could send an intent saying it simply wants someone to open up a web page. In that case, any application that is capable of opening a web page could “compete” to complete this action.

When you have competing applications, the system will ask you which one you’d like to use to complete a given action. You can also set an app as the default. This mechanism works very similarly to your desktop environment, for example, when you downloaded Firefox or Chrome to replace your default Internet Explorer or Safari web browsers.

This type of messaging allows the user to replace any app on the system with a custom one. For example, you might want to download a different SMS application or another browser to replace your existing ones. Figure 5-2 shows how intents can be used to

“jump” between various activities, in the same application or in another app altogether.

You will learn about how to create and use intents in “The Action Bar” on page 148 when we talk about the Action Bar in Android.

Services

Services run in the background and don’t have any user interface components. They can perform the same actions as activities, but without any user interface. Services are useful for actions that you want to perform for a while, regardless of what is on the screen. For example, you might want your music player to play music even as you are flipping between other applications.

Figure 5-2. Intents

Don’t confuse the Android services that are part of an Android app with native Linux services, servers, or daemons, which are much lower-level components of the operating system.

Services have a much simpler life cycle than activities (see Figure 5-3). You either start a service or stop it. Also, the service life cycle is more or less controlled by the developer, and not so much by the system. Consequently, developers have to be mindful to run services so that they don’t consume shared resources unnecessarily, such as the CPU and battery.

Figure 5-3. Service life cycle

Services | 69

Just because a service runs in the background doesn’t necessarily mean it runs on a separate thread. By default, services and activities run on the same main application thread, often called the UI thread. If a service is doing some processing that takes a while to complete (such as performing network calls), you would typically invoke a separate thread to run it. Otherwise, your user interface will run noticeably slower. As of the Honeycomb release of Android, you are actually not even allowed to perform network or other potentially long opera‐

tions on the UI thread.

We’ll look at how to create a new service in Chapter 10.

在文檔中 Learning Android (頁 81-88)