05 - Application Components and Lifecycle - Mihai

Download as doc, pdf, or txt
Download as doc, pdf, or txt
You are on page 1of 14

Application Components and Lifecycle

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.

Android Manifest File (taken from Professional Android Application


Development)

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 An activity tag is required for every Activity displayed by your


application, using the android:name attribute to specify the class name. This must
include the main launch Activity and any other screen or dialogs that can be displayed.
Trying to start an Activity that’s not defined in the manifest will throw a runtime
exception. Each Activity node supports intent-filter child tags that specify which
Intents launch the Activity.

<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.

<service android:enabled=”true” android:name=”.MyService”></service>

 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 As part of the security model, uses-permission tags declare the


permissions you’ve determined that your application needs for it to operate properly. The
permissions you include will be presented to the user, to grant or deny, during
installation. Permissions are required for many of the native Android services,
particularly those with a cost or security implication (such as dialing, receiving SMS, or
using the location-based services). As shown in the item below, third-party applications,
including your own, can also specify permissions before providing access to shared
application components.

<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.

<instrumentation android:label=”My Test”


android:name=”.MyTestClass”
android:targetPackage=”package.aPackage”>
</instrumentation>

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).

To be of use with Context.startActivity(), all activity classes must have a corresponding


<activity> declaration in their package's AndroidManifest.xml. (Taken from
http://developer.android.com/reference/android/app/Activity.html)

For our Sudoku application, lets us look at how the main activity looks like:

package org.example.sudoku;

import android.app.Activity;

public class Sudoku extends Activity {

/** Called when the activity is first created. */


@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

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.

public class Sudoku extends Activity {

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.

/** Called when the activity is first created. */


@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Set the content view

}
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:

 Running: activity is in the foreground


 Paused: activity has lost focus but it is still visible
 Stopped: activity is not visible (completely obscured by another activity)
 Inactive: activity has not been launched yet or has been killed.

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.

 The foreground lifetime of an activity happens between a call to onResume() until a


corresponding call to onPause(). During this time the activity is in front of all other
activities and interacting with the user. An activity can frequently go between the
resumed and paused states -- for example when the device goes to sleep, when an activity
result is delivered, when a new intent is delivered -- so the code in these methods should
be fairly lightweight.

In general the movement through an activity's lifecycle looks like this:

Method Description Killable? Next


Called when the activity is first
created. This is where you should
do all of your normal static set up:
create views, bind data to lists, etc.
This method also provides you with
onCreate() No onStart()
a Bundle containing the activity's
previously frozen state, if there was
one.

Always followed by onStart().


     Called after your activity has been
stopped, prior to it being started
onRestart() again. No onStart()

Always followed by onStart()


Called when the activity is
becoming visible to the user.
onResume() or
onStart() No
Followed by onResume() if the onStop()
activity comes to the foreground, or
onStop() if it becomes hidden.
     onResume() Called when the activity will start No onPause()
interacting with the user. At this
point your activity is at the top of
the activity stack, with user input
going to it.

8
Method Description Killable? Next

Always followed by onPause().


Called when the system is about to
start resuming a previous activity.
This is typically used to commit
unsaved changes to persistent data,
stop animations and other things
that may be consuming CPU, etc.
Implementations of this method
onResume() or
onPause() must be very quick because the next Yes onStop()
activity will not be resumed until
this method returns.

Followed by either onResume() if


the activity returns back to the front,
or onStop() if it becomes invisible
to the user.
Called when the activity is no
longer visible to the user, because
another activity has been resumed
and is covering this one. This may
happen either because a new
activity is being started, an existing
onRestart()
one is being brought in front of this
onStop() Yes or
one, or this one is being destroyed. onDestroy()

Followed by either onRestart() if


this activity is coming back to
interact with the user, or
onDestroy() if this activity is
going away.
The final call you receive before
your activity is destroyed. This can
happen either because the activity is
finishing (someone called finish()
on it, or because the system is
onDestroy() Yes nothing
temporarily destroying this instance
of the activity to save space. You
can distinguish between these two
scenarios with the isFinishing()
method.

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:

Figure 4.2 Main Screen for our Sudoku application

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:

Figure 1.3 Provides more information about the Sudoku game

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.

 Intent objects passed to any of the broadcast methods (suchas


Context.sendBroadcast(), Context.sendOrderedBroadcast(), or
Context.sendStickyBroadcast()) are delivered to all interested broadcast receivers.
Many kinds of broadcasts originate in system code.

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:

<?xml version="1.0" encoding="utf-8"?>


<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.example.sudoku"
android:versionCode="1"
android:versionName="1.0.0">
<application android:icon="@drawable/icon"
android:label="@string/app_name">
<activity android:name=".Sudoku"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

13
</activity>

</application>
</manifest>

The filter in our Sudoku example — the combination of the action


"android.intent.action.MAIN" and the category "android.intent.category.LAUNCHER" —
is a common one. It marks the Sudoku Activity as one that should be represented in the
application launcher, the screen listing applications users can launch on the device. In other
words, the activity is the entry point for the application, the initial one users would see when they
choose the application in the launcher.

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

You might also like