Course Module: Application Components and Lifecycle - FAU Android

shrewdnessmodernMobile - sans fil

14 déc. 2013 (il y a 3 années et 7 mois)

88 vue(s)


1

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
th
e 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
. I
t 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 Acti
vity starting the next one.



Services
.

A Service is a compon
ent 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 ar
e used to
perform regular
processing
that needs
to continue
even when your application
’s Activities are
not active or visible.

As an
e
xample, a Service might
fetch data over the network
,

in

the background, while the user
normally interacts with the applica
tion.



Content Providers
.

When you want
specific data to b
e

available to other applications,
y
ou 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 tha
t 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

s
pecify 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.
The
re 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, de
termines 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.


2


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

fi
le. A typical manifest node is shown in the XML snipp
et below:

<manifest

x
mlns:android=http://schemas.android.com/apk/res/android



package=”com.my_domain.my_app”>


[ ... manifest nodes ... ]

</manifest>


The
manife
st

tag includes nodes that defi
ne the application components, security settings, and
test

cla
sses 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
specif
y

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 spe
cify the class name. This must
include the

main launch Activity and any other screen or dialogs that can be displayed.
Trying to

st
art an Activity that’s not defi
ned 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.categor
y.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 andro
id: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.



3

<provider
android
:permission=”
package
.MY_PERMISSION”


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

havin
g to launch your application fi
rst. 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 Re
ceiver 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

p
ermissions

you’ve determined that your application needs for it to operate properl
y. 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, o
r
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 applicat
ion component, you need to
defi
ne

a permission in the manifest. Use the
permission
tag
to create these permission
defi
nitions.

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>



4



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 a
ndroid: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 automati
cally creates a new manifest fi
le when it creates a new
project.



Activities


An activity is a single, focused thing that the user ca
n 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 w
ill 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 use
r 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/re
ference/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);


5



//
Set the content view







}





@Override


protected

void

onResume() {


super
.onResume();


//
S
tart 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 modul
es.
Let us examine
, at a high level,

our main a
ctivity,
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 w
e refer
ence 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 {


Ac
tivities are classes inheriting from the
android.app.Activity

base class.
These implies
that all the (public and protected) method
s
from the base c
l
a
ss are vis
ible 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 sup
erclass so as to make sure that
the Android
activity
initialization
is done.


@Override


protected

void

onResume() {


6


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
,
o
nResume

(other will also
be mentioned later).

To understand when each method is b
eing called, it is important to
understand
the Activity lifecycle shown
in Figure
4.1
.





7


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 h
as 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
().


8



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 in
tent 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

onCreate()

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
a Bundle contai
ning the activity's
previously frozen state, if there was
one.

Always followed by
onStart()
.

No

onStart()






onRestart()

Called after your activity ha
s been
stopped, prior to it being started
again.

Always followed by
onStart()

No

onStart()

onStart()

Called when the activity is
becoming visible to the
user.

Followed by
onResume()

if the
activity comes to the foreground, or
onStop()

if it becomes hidden.

No

onResume()

or
onStop()






onResume()

Called

when the activity will start
interacting with the user. At this
point your activity is at the top of
the activity stack, with user input
going to it.

No

onPause()


9

Method

Description

Killable?

Next

Always followed by
onPause()
.

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
must be very quick because the next
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.

Yes

onRes
ume()

or

onStop()

onStop()

Called when the activity is no
longer visible to the user, because
another activity has been resumed
and is covering this one. T
his may
happen either because a new
activity is being started, an existing
one is being brought in front of this
one, or this one is being destroyed.

Followed by either
onRestart()

if
this activity is coming back to
interact with the user, or
onDestroy()

if this activity is
going away.

Yes

onRestart()

or

onDestroy()

onDestroy()

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
temporarily destroying this instance
of the activity to sav
e space. You
can distinguish between these two
scenarios with the
isFinishing()

method.

Yes

nothing


Note the "Killable" column in the above table
--

f
or those methods that are marked as being
killable, after that method returns the process hosting the activity may killed by the system
at any

10

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 rece
ived 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 met
hod 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://d
eveloper.android.com/reference/android/app/Activity.html
)

Looking at our Sudoku example, we will go through
some

screens where t
he menu is being
displayed,
the user chooses the option to
find out more about the game
, goes back to the main
menu, and choos
es 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



11

This actually represents the Sudoku Activity which code was presented previously. Wh
en 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 Ac
tivity:




F
igure
1
.3

Provides more in
formation 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 t
he phone, the
screen in
Figure 4.2

reappears and the
onResume

method o
f 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 w
ould no longer be visible to the user (as shown
in Figure 4
.4
), thus the
onStop

method would get called.



12


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
li
fecycle
.
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 start
ed 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 inte
nt itself, an
Intent

object, is a passive data structure holding an abstract description of an operation to be performed

13



or, in the case of broadcasts, a description of so
mething 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 ac
tivity or get an existing activity
to do something new.



An Intent object is passed to
Context.startService()

to initiate a ser
vice 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 (such as
Context.sendBroadcast()
,
Context.sendOrderedBroadcast()
, or
Context.sendStickyBroadcast()
) are deliv
ered 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 receiv
er, 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
st
artActivity 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 t
hat
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 po
tential 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

an
droid: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
>


14


</
activity
>







</
application
>

</
manifest
>


The filter in our Sudoku example


the combination of the action
"
android.inte
nt.action.MAIN
" and the category "
android.intent.category.LAUNCHER
"


is a common one. It marks the
Sudoku A
ctivity as one that should be represented in the
application launcher, the screen listing applications users can launch on the device. In other
word
s, 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