Application Components and Lifecycle



Download 79.02 Kb.
Date20.06.2017
Size79.02 Kb.
#21153

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.


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:

package=”com.my_domain.my_app”>

[ ... manifest nodes ... ]


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.



android:theme=”@style/my_theme”>

[ ... application nodes ... ]




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















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

android:name=”.MyContentProvider”

android:enabled=”true” android:authorities=”package.myapp.MyContentProvider”>



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


android:label=”My Broadcast Receiver”

android:name=”.MyBroadcastReceiver”>




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







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


android:protectionLevel=”dangerous”

android:label=”Self Destruct”

android:description=”@string/detonate_description”>





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


android:name=”.MyTestClass”

android:targetPackage=”package.aPackage”>


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

// 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() {

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.




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

  • 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

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

Always followed by onStart().



No

onStart()

    

onRestart()

Called after your activity has 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.

Always followed by onPause().



No

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

onResume() 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. This 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 save space. You can distinguish between these two scenarios with the isFinishing() method.

Yes

nothing

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


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 — 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 (such as 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:
"1.0" encoding="utf-8"?>

"http://schemas.android.com/apk/res/android"

package="org.example.sudoku"

android:versionCode="1"

android:versionName="1.0.0">



"@drawable/icon"

android:label="@string/app_name">



".Sudoku"

android:label="@string/app_name">





"android.intent.action.MAIN" />

"android.intent.category.LAUNCHER" />








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







Download 79.02 Kb.

Share with your friends:




The database is protected by copyright ©ininet.org 2024
send message

    Main page