05 - Application Components and Lifecycle - Mihai
05 - Application Components and Lifecycle - Mihai
05 - Application Components and Lifecycle - Mihai
Application Components
An Android application consists of components that are coupled together; each component can
be the entry point in your application, rather than having one single entry point for everything in
the application (like the main() function for C/C++/Java). The building blocks for your
application are provided by the following components:
Activities. An Activity is usually one screen of your application, hence there could be
one or more Activities per application. It represents the user interface, the application’s
presentation layer. To display information and respond to user actions, Activities use
Views to form the graphical user interface. The transition between Activities is done by
having one Activity starting the next one.
Services. A Service is a component that runs in the background, thus not having a visual
user interface. Because of this, it will not interact with the user, but rather it will do some
work silently, invisibly, for you. They are used to perform regular processing that needs
to continue even when your application’s Activities are not active or visible. As an
example, a Service might fetch data over the network, in the background, while the user
normally interacts with the application.
Content Providers. When you want specific data to be available to other applications,
you will use a Content Provider. The data can be stored in a SQLite database, or in a File,
and you can configure your own Content Provider to permit access to that data. For
example, on an Android phone, there is a specific Content Provider to access the contact
information.
Broadcast Receivers. A Broadcast Receiver receives and reacts to broadcast messages.
When you have an event-driven environment, and you have to be able to listen for events
and act in response, then you will register a Broadcast Receiver to listen for events that
match a specific filter criteria, and execute the desired action afterwards.
Intents. Intents, or asynchronous messages, are used to specify what intentions you have
in terms of a specific action being performed; mainly, you use them to activate other
components of your application. The content of the message, for activities and services,
names the action being requested, and specifies the URI of the data to act on, among
other things.
All these components are bound together using a project manifest that describes each component
and how they interact. There is one manifest file per application, called
AndroidManifest.xml. It includes nodes for each of the components (Activities, Services,
Content Providers, and Broadcast Receivers) that make up your application and, using Intent
Filters and Permissions, determines how they interact with each other and other applications. It
also offers attributes to specify application metadata (like its icon or theme), and additional top-
level nodes can be used for security settings and unit tests as described below.
1
The manifest is made up of a root manifest tag with a package attribute set to the project’s
package. It usually includes an xmlns:android attribute that supplies several system attributes
used within the file. A typical manifest node is shown in the XML snippet below:
<manifest
xmlns:android=http://schemas.android.com/apk/res/android
package=”com.my_domain.my_app”>
[ ... manifest nodes ... ]
</manifest>
The manifest tag includes nodes that define the application components, security settings, and
test classes that make up your application. The following list gives a summary of the available
manifest node tags, and an XML snippet demonstrating how each one is used:
application A manifest can contain only one application node. It uses attributes to
specify the metadata for your application (including its title, icon, and theme). It also acts
as a container that includes the Activity, Service, Content Provider, and Broadcast
Receiver tags used to specify the application components.
<application android:icon=”@drawable/icon”
android:theme=”@style/my_theme”>
[ ... application nodes ... ]
</application>
<activity android:name=”.MyActivity”
android:label=”@string/app_name”>
<intent-filter>
<action android:name=”android.intent.action.MAIN” />
<category
android:name=”android.intent.category.LAUNCHER” />
</intent-filter>
</activity>
service As with the activity tag, create a new service tag for each Service class
used in your application. Service tags also support intent-filter child tags to allow
late runtime binding.
provider Provider tags are used for each of your application’s Content Providers.
Content Providers are used to manage database access and sharing within and between
applications.
<provider android:permission=”package.MY_PERMISSION”
2
android:name=”.MyContentProvider”
android:enabled=”true”
android:authorities=”package.myapp.MyContentProvider”>
</provider>
receiver By adding a receiver tag, you can register a Broadcast Receiver without
having to launch your application first. Broadcast Receivers are like global event listeners
that, once registered, will execute whenever a matching Intent is broadcast by an
application. By registering a Broadcast Receiver in the manifest, you can make this
process entirely autonomous. If a matching Intent is broadcast, your application will be
started automatically and the registered Broadcast Receiver will be run.
<receiver android:enabled=”true”
android:label=”My Broadcast Receiver”
android:name=”.MyBroadcastReceiver”>
</receiver>
<uses-permission android:name=”android.permission.ACCESS_LOCATION”>
</uses-permission>
permission Before you can restrict access to an application component, you need to
define a permission in the manifest. Use the permission tag to create these permission
definitions. Application components can then require them by adding the
android:permission attribute. Other applications will then need to include a uses-
permission tag in their manifests (and have it granted) before they can use these
protected components.
Within the permission tag, you can specify the level of access the permission will
permit (normal, dangerous, signature, signatureOrSystem), a label, and an
external resource containing the description that explain the risks of granting this
permission.
<permission android:name=”package.DETONATE_DEVICE”
android:protectionLevel=”dangerous”
android:label=”Self Destruct”
android:description=”@string/detonate_description”>
</permission>
3
instrumentation Instrumentation classes provide a framework for running tests on
your Activities and Services at run time. They provide hooks to monitor your application
and its interaction with the system resources. Create a new node for each of the test
classes you’ve created for your application.
A more detailed description of the manifest and each of these nodes can be found at
http://code.google.com/android/devel/bblocks-manifest.html
The ADT New Project Wizard automatically creates a new manifest file when it creates a new
project.
Activities
An activity is a single, focused thing that the user can do. Almost all activities interact with the
user, so the Activity class takes care of creating a window for you in which you can place your
UI with setContentView(View). While activities are often presented to the user as full-screen
windows, they can also be used in other ways: as floating windows (via a theme with
windowIsFloating set) or embedded inside of another activity (using ActivityGroup). There are
two methods almost all subclasses of Activity will implement:
onCreate(Bundle) is where you initialize your activity. Most importantly, here you will
usually call setContentView(int) with a layout resource defining your UI, and using
findViewById(int) to retrieve the widgets in that UI that you need to interact with
programmatically.
onPause() is where you deal with the user leaving your activity. Most importantly, any
changes made by the user should at this point be committed (usually to the
ContentProvider holding the data).
For our Sudoku application, lets us look at how the main activity looks like:
package org.example.sudoku;
import android.app.Activity;
4
// Set the content view
…
@Override
protected void onResume() {
super.onResume();
// Start the music
}
@Override
protected void onPause() {
super.onPause();
// Stop the music
}
At this stage of the course, you do not need to understand all the elements in the code. We will
cover them as we go through other modules. Let us examine, at a high level, our main activity,
Sudoku, piece by piece:
package org.example.sudoku;
import android.app.Activity;
The package declaration is the same as the one used when creating the project in Eclipse. Any
classes that we reference need to be imported, hence all the import statements general to any
other Java project, but specific in terms of the actual classes imported. Most of the Android-
specific classes are in the android package.
Activities are classes inheriting from the android.app.Activity base class. These implies
that all the (public and protected) methods from the base class are visible in our own activity
class.
}
The method that is being called when our activity is first created is onCreate. The first thing we
do is chain up to the superclass so as to make sure that the Android activity initialization is done.
@Override
protected void onResume() {
5
super.onResume();
// Start the music
}
@Override
protected void onPause() {
super.onPause();
// Stop the music
}
Since our end application will also involve music, in the two methods above (which are
explained in more details in the next sections), we start and stop the music.
The main methods of our Sudoku Activity are onCreate, onPause, onResume (other will also
be mentioned later). To understand when each method is being called, it is important to
understand the Activity lifecycle shown in Figure 4.1.
6
Figure 4.1 Activity Lifecycle State Diagram
Activities are managed as an activity stack (a LIFO collection). An Activity has four possible
states:
There are three key loops you may be interested in monitoring within your activity:
The entire lifetime of an activity happens between the first call to onCreate(Bundle)
through to a single final call to onDestroy(). An activity will do all setup of "global" state
in onCreate(), and release all remaining resources in onDestroy(). For example, if it has a
thread running in the background to download data from the network, it may create that
thread in onCreate() and then stop the thread in onDestroy().
7
The visible lifetime of an activity happens between a call to onStart() until a
corresponding call to onStop(). During this time the user can see the activity on-screen,
though it may not be in the foreground and interacting with the user. Between these two
methods you can maintain resources that are needed to show the activity to the user. For
example, you can register a BroadcastReceiver in onStart() to monitor for changes that
impact your UI, and unregister it in onStop() when the user an no longer see what you are
displaying. The onStart() and onStop() methods can be called multiple times, as the
activity becomes visible and hidden to the user.
8
Method Description Killable? Next
Note the "Killable" column in the above table -- for those methods that are marked as being
killable, after that method returns the process hosting the activity may killed by the system at
9
any time without another line of its code being executed. Because of this, you should use the
onPause() method to write any persistent data (such as user edits) to storage. In addition, the
method onSaveInstanceState(Bundle) is called before placing the activity in such a background
state, allowing you to save away any dynamic instance state in your activity into the given
Bundle, to be later received in onCreate(Bundle) if the activity needs to be re-created. See the
Process Lifecycle section for more information on how the lifecycle of a process is tied to the
activities it is hosting. Note that it is important to save persistent data in onPause() instead of
onSaveInstanceState(Bundle) because the later is not part of the lifecycle callbacks, so will not
be called in every situation as described in its documentation.
For those methods that are not marked as being killable, the activity's process will not be killed
by the system starting from the time the method is called and continuing after it returns. Thus an
activity is in the killable state, for example, between after onPause() to the start of onResume().
(Taken from http://developer.android.com/reference/android/app/Activity.html)
Looking at our Sudoku example, we will go through some screens where the menu is being
displayed, the user chooses the option to find out more about the game, goes back to the main
menu, and chooses to start a new game. When the application is being started, the first screen is
the one shown in Figure 4.2 below:
10
This actually represents the Sudoku Activity which code was presented previously. When this
Activity is first started, the onCreate, onStart, and onResume methods are called in this
order. When the user choose the “About” option (by pressing the respective button), the About
Activity is being started from inside the Sudoku Activity:
At this point, the onPause method of our Sudoku Activity is being called because another
activity (the About Activity) came in front of it. If we press the back button of the phone, the
screen in Figure 4.2 reappears and the onResume method of the Sudoku Activity is called since
our activity is still visible but has lost focus. If we were to actually start a new game (by pressing
the “New Game” button), our Sudoku Activity would no longer be visible to the user (as shown
in Figure 4.4), thus the onStop method would get called.
11
Figure 4.4 The Game screen for our Sudoku application
Since each activity is hosted separately by a process, it is worth mentioning the process lifecycle.
To free up resources, processes are being killed based on their priority:
Critical Priority: foreground (active) processes
– Foreground activities; components that execute an onReceive event handler;
services that are executing an onStart, onCreate, or onDestroy event handler.
High Priority: visible (inactive) processes and started service processes
– Partially obscured activity (lost focus); services started.
Low Priority: background processes
– Activities that are not visible; activities with no started service
You can find out more about Activities by visiting the web address below:
http://developer.android.com/reference/android/app/Activity.html
Intents
Three of the core components of an application — activities, services, and broadcast receivers —
are activated through messages, called intents. Intent messaging is a facility for late run-time
binding between components in the same or different applications. The intent itself, an Intent
object, is a passive data structure holding an abstract description of an operation to be performed
12
— or, in the case of broadcasts, a description of something that has happened and is being
announced. There are separate mechanisms for delivering intents to each type of component:
An Intent object is passed to Context.startActivity() or
Activity.startActivityForResult() to launch an activity or get an existing activity
to do something new.
An Intent object is passed to Context.startService() to initiate a service or deliver
new instructions to an ongoing service. Similarly, an intent can be passed to
Context.bindService() to establish a connection between the calling component and a
target service. It can optionally initiate the service if it's not already running.
In each case, the Android system finds the appropriate activity, service, or set of broadcast
receivers to respond to the intent, instantiating them if necessary. There is no overlap within
these messaging systems: Broadcast intents are delivered only to broadcast receivers, never to
activities or services. An intent passed to startActivity() is delivered only to an activity,
never to a service or broadcast receiver, and so on. (Taken from
http://developer.android.com/guide/topics/intents/intents-filters.html)
If we take a look at our Sudoku Activity, there is a call to the startActivity method being made
when we want to find out more about the game:
case R.id.about_button:
Intent i = new Intent(this, About.class);
startActivity(i);
break;
An Intent object can explicitly name a target component. If it does, Android finds that
component (based on the declarations in the manifest file) and activates it. But if a target is not
explicitly named, Android must locate the best component to respond to the intent. It does so by
comparing the Intent object to the intent filters of potential targets. A component's intent filters
inform Android of the kinds of intents the component is able to handle. Like other essential
information about the component, they're declared in the manifest file. Below is an excerpt from
our Sudoku game, the AndroidManifest.xml file:
13
</activity>
…
</application>
</manifest>
A component can have any number of intent filters, each one declaring a different set of
capabilities. If it doesn't have any filters, it can be activated only by intents that explicitly name
the component as the target.
You can find out more about Intent and Intent Filters by visiting the web address below:
http://developer.android.com/guide/topics/intents/intents-filters.html
14