Android Application Development
Total Page:16
File Type:pdf, Size:1020Kb
3 . A p p l i c a t i o n ’ s L i f e c y c l e | 1 Lesson 3. Applications's Life Cycle 3 . A p p l i c a t i o n ’ s L i f e c y c l e | 2
Lesson 3 Application’s Life-Cycle
Goals
In this lesson, we study how typical Android applications are made and executed. We briefly discuss the four essential components of applications. A sample app - called the LifeCycleTour app - is introduced to illustrate how the cycle of creation, execution, and finally termination is experienced by an application that consists of a simple activity.
Android’s Core Components
Android's core components are the primordial classes or building blocks from which apps are made. Components work in a cooperative mode, each contributing somehow to the completion of the tasks undertaken by the app. Each kind of core component provides a particular type of functionality and has a distinct lifecycle. A lifecycle defines how the core object is created, transitioned, and destroyed. An Android application usually includes of one or more of the following core components: Activities, Services, Broadcast Receivers, and Content Providers.
The Activity Class
An Activity object is similar to a Windows-Form. It usually presents a single graphical visual interface (GUI or UI) which in addition to the displaying/collecting of data, provides some form of ‘code-behind‘ functionality. A typical Android application contains one or more Activity objects. Applications must designate one particular activity as their main task or entry point. That activity is the first code to be executed when the app is launched. An activity may transfer control and data to another activity through an inter-process communication protocol called Intents. For example, a login activity may show a screen to enter user name and password and a proceed button. After clicking its button, some authentication process is applied on the data, and before the login activity terminates, some other activity is called. Figure 3.1 provides another example of an app exposing multiple UIs. The Google Play Store app allows its users to browse into two main categories (1) Apps and Games, and (2) Music, Movies, Books. Assume the user is looking for a movie and taps on the icon representing the film "Logan." The new screen (Figure 3.1.b) gives a summary of the movie, its reviews, and additional choices to drill down in the search for other Action-Adventure and Similar releases. Figure 3.1.c shows the listing supplied for the option Action-Adventure films. Each of the screens in Figure 3.1 is likely to be controlled by an independent activity (or an Android Fragment object, which will be studied in Lesson 6.) 3 . A p p l i c a t i o n ’ s L i f e c y c l e | 3
a. Google Play Store App b. Selecting a particular film c. Action & Adventures Figure 3.1 Google Play Store app © showing three user interfaces, each likely tied to an independent activity 1
The Service Class
A Services is a type of activity that does not have a visual user interface and does not interact with the user directly. A service instance may be active and occupied without the user noticing its presence. Services are analogous to secondary threads, usually hosting some kind of background 'busy- work', which may run for an indefinite period of time. Applications start their own services or connect to services already active. A service runs according to its lifecycle scheme, which is different from that of activities. Therefore, a service may survive an application that uses it. As an example, consider your background GPS service. It could be enabled to quietly run in the background detecting location information from satellites, phone towers or Wi-Fi routers. The service periodically broadcasts location coordinates to any app listening for that kind of data; for instance a route guidance app such as Google Mobile Maps App© [2] or a real estate app such as Zillow © [3]. Any application requesting location services may opt for binding to the running GPS service and use the data that it supplies.
Example 3.1 The Multitasking Golfer Imagine you are enjoying a round of golf with a restless friend. He is listening to a soothing music radio service on his phone. On occasions, he looks on the phone for golf course related data such as how close a green, a creek, or a bunker is from his current location. This course information is based on actual readings made by the GPS hardware on behalf of the device’s location service. Assume our friend claims that in order
1 Google Play Store ©, Google Mobile, Zillow and Angry Birds applications are copyrighted and all rights belong to their corresponding creators. 3 . A p p l i c a t i o n ’ s L i f e c y c l e | 4 to relax from the ‘stress’ of playing golf, he needs to periodically switch to a distracting video game such as Angry Birds ©4 while waiting for his turn to hit the ball. In this scenario, the radio and location services, run in the background without an interface. Only when needed the user may stop the game, pause the radio, read course data, and finally hit the ball.
The Broadcast Receiver class
A BroadcastReceiver is a dedicated listener that waits for a triggering system-wide message to do some work. The message could be something like low-battery, Wi-Fi connection available, breaking news, earth- quakes in California, speed-camera nearby. Broadcast receivers do not display a user interface. They typically register with the system by means of a filter acting as a key. When the broadcasted message matches the key the receiver is activated. A broadcast receiver could respond by either executing a specific activity or use the notification mechanism to request the user's attention.
Figure 3.2 An example of a Background Service communicating with a matching Broadcast Receiver.
The Content Provider Class
A content provider is a data-centric service that shares persistent datasets with any number of applications. Common global datasets include contacts, pictures, messages, audio files, emails. The global datasets are usually stored in a SQLite database (however the developer does not need to be a SQL expert) The content provider class offers a standard set of parametric methods to enable other applications to retrieve, delete, update, and insert data items. 3 . A p p l i c a t i o n ’ s L i f e c y c l e | 5
Figure 3.3 A content Provider supports retrieval and maintenance of global datasets
Life and Death in Android
Each Android application runs inside its private instance of a Virtual Machine (VM). At any point in time, we may have several simultaneous VM instances in an active state (real parallelism as opposed to task switching). Unlike a common Windows or UNIX process, an Android application does not completely control the completion of its lifecycle. Occasionally hardware resources may become critically low and the OS could order early termination of any process. The decision considers factors such as number and age of the application’s components currently running, relative importance of those components to the user, and how much free memory is available in the system.
The Activity Stack
Activities in the Android OS System are scheduled using an activity stack. When a new activity is started, it is placed on top of the stack to become the running activity. The previous activity is pushed-down one level in the stack, and may come back to the foreground once the new activity finishes. If the user presses the Back Button the current activity is terminated and the previous activity on the stack moves up to become active. Android 4.0 introduced the ‘Recent app’ button to arbitrarily pick as active any entry currently in the stack (more on this issue later)
Figure 3.4 Virtual buttons: Back, Home, and Recent-Apps shown on two different devices.
Figure 3.5 illustrates the moment the system initiates a new activity. The running activity is pushed on the stack and control and visibility is granted to the new arrival. In case the system resources are tight an older entry is the system stack may be chosen for termination releasing all resources assigned to it. 3 . A p p l i c a t i o n ’ s L i f e c y c l e | 6
Figure 3.5 Android’s stack-oriented approach to activity execution
Activity Life Cycle
All Android activities, execute according to a master plan that includes a beginning, an end, and a sequence of in-between states. During its passing through those states (or hooks) the activity will acquire the following descriptors: active, inactive, visible or invisible. Stepping from one point to the next in an activity’s life-cycle is guided by an established path of pre- defined states. Figure 3.6 illustrates the sequence of Life-Cycle events which are followed from the beginning to the end of an activity’s execution. Observe the diagram consists of nodes and links. Nodes represent states, and links identify transition (or callback) methods. A typical activity will experience the sequence of states: Created, Started, Resumed, Paused, Stopped, and finally Destroyed. When an activity reaches the Resumed state, it becomes visible and active. At this point, the exposed activity can use its graphical interface to interact with the user. According to the Life-Cycle diagram, a Paused activity has choices; it either turns into Stopped or goes back to be Resumed. Similarly, a Stopped activity could be Started and then Resumed. Moving along the nodes of the life-cycle diagram is done through the invocation of transition methods. When an application is first launched the Operating System calls the onCreate() method to allow the main activity to enter the Created state. The links in Figure 3.6 are labeled with the transition method that grants admission to the next state. The transition methods include onCreate(), onStart(), onRestart(), onResume(), onPause(), onStop(), and onDestroy().
onCreate() is the only mandatory callback method, and all apps must provide an implementation of it. Generally, simple apps are entirely written inside this single transition method. However, you may add other recommended callback methods to produce a more refined behavior specification. Additional methods are useful in responding to situations such as your app is paused because of an incoming call, or it is terminated, or the device is rotated, or the battery is low, etc. 3 . A p p l i c a t i o n ’ s L i f e c y c l e | 7
Figure 3.6 Activity Life-Cycle Diagram.
Keep in mind that not all of the callback methods are required for an app to work. Each activity must decide what is important to it and then act upon this choices. Consequently, some of the callback entries could be completely ignored.
Example 3.2 A skeleton activity showing common callback methods The following Java code is used to illustrate the structure of a typical Android Activity. The program consists of a collection of callback methods (or 'hooks') that are executed when the activity makes a transition to the corresponding state (see Figure 3.6). For instance, the onCreate(Bundle saveInstanceState) method is executed when the application begins to work. The optional Bundle argument is an associative-array like container in which the application may save state data. Observe that not all the phases shown in Figure 3.6 need to be implemented by an activity (the only exception is of onCreate).
Example 3.2 Skeleton of a typical Android Activity public class MainActivity2 extends Activity { @Override public void onCreate (Bundle savedInstanceState) { super.onCreate(savedInstanceState); // The activity is being created. } @Override protected void onStart() { super.onStart(); // The activity is about to become visible. } @Override protected void onResume() { super.onResume(); // The activity has become visible (it is now "resumed"). } @Override protected void onPause() { super.onPause(); // Another activity is taking focus 3 . A p p l i c a t i o n ’ s L i f e c y c l e | 8
// (this activity is about to be "paused"). } @Override protected void onStop() { super.onStop(); // The activity is no longer visible // (it is now "stopped") } @Override protected void onDestroy() { super.onDestroy(); // The activity is about to be destroyed. } }
Life-Cycle Methods
onCreate() must be implemented by each activity to do its initial setup. This mandatory method is executed only once on the activity’s lifetime. It is typically used to initialize the application’s data structures, wire-up UI view elements (buttons, text boxes, lists) with local Java objects, define listeners’ behavior, execute threads, start services, etc. It may receive a data Bundle object containing the activity's previous state (if any have been saved). onPause() should be implemented whenever the application has some important data to be committed so it could be reused. This highly recommended method is called when the system is about to transfer control to another activity. In addition to safely writing uncommitted data, it may be used to stop any work in progress. The next activity waits until completion of this state. Followed either by onResume() if the activity returns to the foreground, or by onStop() if it becomes invisible to the user. A paused activity could be killed by the system.
Killable States
Android OS may terminate any activity whenever the resources needed to run other operations of higher importance are critically low.
When an activity reaches the methods: onPause(), onStop(), and onDestroy() it becomes killable.
onPause() is the only state that is guaranteed to have a chance to complete before the process is terminated. Consequently, you should use onPause()to write any pending persistent data.
Data Persistence using Android SharedPreferences Class
SharedPreferences is a simple Android persistence mechanism used to store and retrieve
SharedPreferences myPrefFile1 = getSharedPreferences("myPrefFile1", Activity.MODE_PUBLIC) 3 . A p p l i c a t i o n ’ s L i f e c y c l e | 9
Figure 3.7 Android Device Monitor showing the placement of an application’s SharedPreference file.
SharedPreference files are permanently stored in the application’s process space (see Figure 3.7). You may use the Android Device Monitor tool to locate the entry: data/data/your-package-name/shared-prefs. Persistence is an important concept in Android, and it is discussed in more detail in a later lesson.
Example 3.3 The Life-Cycle Tour App The Life-Cycle Tour application consists of a single activity that implements a hook for each of the major transition methods shown in Figure 3.6. The app also includes logic to save the user's preference for a background color. This background color is re-applied to the app’s screen each time it is resumed (as it happens when the device is rotated). Some design and functional facts about the app follow.
Each time the activity invokes a callable method a Toast is displayed showing the current event’s name.
An EditText box is provided for the user to type-in a background color (red, green, blue, and white.) When the activity is paused, the selected background color value must be saved into a SharedPreferences container. When the application is resumed, the last choice of background color should be applied. An EXIT button should be provided to terminate the app. You are asked to observe the sequence of messages displayed when the application Loads for the first time Is paused after clicking the HOME button Is re-executed from the Launch-Pad Is terminated by pressing BACK and its own EXIT button Is re-executed after a background color is chosen. 3 . A p p l i c a t i o n ’ s L i f e c y c l e | 10
Example 3.3 Layout Specification (activity_main.xml)
Observe that the
Example 3.3 Activity’s Java code implementation public class MainActivity extends Activity {
//class variables 3 . A p p l i c a t i o n ’ s L i f e c y c l e | 11 private Context context; private int duration = Toast.LENGTH_SHORT; //PLUMBING: Pairing GUI controls with Java objects private Button btnExit; private EditText txtColorSelected; private TextView txtSpyBox; private LinearLayout myScreen; private String PREF_FILE_NAME = "myPrefFile1";
@Override protected void onCreate(Bundle savedInstanceState) { requestWindowFeature(Window.FEATURE_ACTION_BAR); super.onCreate(savedInstanceState);
//display the main screen ❶
setContentView(R.layout.activity_main);
//wiring GUI controls and matching Java objects txtColorSelected = (EditText)findViewById(R.id.editColor); btnExit = (Button) findViewById(R.id.btnExit); txtSpyBox = (TextView)findViewById(R.id.txtSpy); myScreen = (LinearLayout)findViewById(R.id.myScreen1);
//set GUI listeners, watchers,... btnExit.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { finish(); } });
//observe (text) changes made to EditText box (color selection) ❷
txtColorSelected.addTextChangedListener(new TextWatcher() { @Override public void onTextChanged(CharSequence s, int start, int before, int count) { // nothing TODO, needed by interface }
@Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { // nothing TODO, needed by interface }
@Override public void afterTextChanged(Editable s) { 3 . A p p l i c a t i o n ’ s L i f e c y c l e | 12
//set background to selected color String chosenColor = s.toString().toLowerCase(Locale.US); txtSpyBox.setText(chosenColor); setBackgroundColor(chosenColor, myScreen); } }); //show the current state's name context = getApplicationContext(); Toast.makeText(context, "onCreate", duration).show(); } //onCreate
@Override protected void onDestroy() { super.onDestroy(); Toast.makeText(context, "onDestroy", duration).show(); }
@Override ❸ protected void onPause() { super.onPause(); //save state data (background color) for future use String chosenColor = txtSpyBox.getText().toString();
saveStateData(chosenColor);
Toast.makeText(context, "onPause", duration).show(); }
@Override protected void onRestart() { super.onRestart(); Toast.makeText(context, "onRestart", duration).show(); } @Override protected void onResume() { super.onResume(); Toast.makeText(context, "onResume", duration).show(); }
@Override ❹ protected void onStart() { super.onStart(); //if appropriate, change background color to chosen value updateMeUsingSavedStateData();
Toast.makeText(context, "onStart", duration).show(); 3 . A p p l i c a t i o n ’ s L i f e c y c l e | 13
}
@Override protected void onStop() { super.onStop(); Toast.makeText(context, "onStop", duration).show(); }
private void setBackgroundColor(String chosenColor, LinearLayout myScreen) { ❺
//hex color codes: 0xAARRGGBB AA:transp, RR red, GG green, BB blue
if (chosenColor.contains("red"))
myScreen.setBackgroundColor(0xffFFCDD2); //Red100, Color.RED if (chosenColor.contains("green")) myScreen.setBackgroundColor(0xffC8E6C9); //Green100, Color.GREEN if (chosenColor.contains("blue")) myScreen.setBackgroundColor(0xffBBDEFB); //Blue100, Color.BLUE if (chosenColor.contains("white")) myScreen.setBackgroundColor(0xffffffff); //Color.WHITE } //setBackgroundColor
private void saveStateData(String chosenColor) { ❻
//this is a little
private void updateMeUsingSavedStateData() { ❼
// (in case it exists) use saved data telling back color SharedPreferences myPrefContainer = getSharedPreferences(PREF_FILE_NAME, Activity.MODE_PRIVATE);
String key = "chosenBackgroundColor"; String defaultValue = "white"; 3 . A p p l i c a t i o n ’ s L i f e c y c l e | 14
if ((myPrefContainer != null) && myPrefContainer.contains(key)) { String color = myPrefContainer.getString(key, defaultValue); setBackgroundColor(color, myScreen); txtSpyBox.setText(color); }
}//updateMeUsingSavedStateData
} //Activity
Comments
1. The onCreate method is the busiest callback in this example. In addition to displaying a brief Toast message announcing the function's name (all of our callbacks will do the same), it has other responsibilities. First, it makes a call to setContentView() to display the application's screen. Then, it performs a set of 'plumbing' (or 'hard-wiring') operations in which our four UI widgets are matched to Java objects. In this example we have a button (btnExit), a TextView (txtSpyBox), an EditText (txtColorSelected), and a layout (myScreen). The button object receives an onClick listener to react to the tap event. When that happens, the application is terminated by calling the finish() function. Finally, the EditText box is given a text monitoring watcher.
2. The TextWatcher mechanism is activated each time the text inside the box is modified. There are three mandatory entries associated with the interface. We have chosen the afterTextChanged function to implement the logic for selecting a background color. When the user types in one of the valid possibilities (red, green, or blue) the method setBackgroundColor is called to paint the screen with the chosen color. Observe that the argument s is an Editable field (instead of String). An Editable object is very similar to an immutable string, but unlike strings, its content can be affected with HTML markup tags.
3. The onPause method is responsible for saving in a persistent file the user's choice of background color.
4. Each time the onStart method is called we make sure that state data previously saved is restored into the application. In our example, this refers to re-applying to the screen the selected background color.
5. The utility function setBackgroundColor() matches a piece of text to an RGB color value. For instance, if the user selects 'red' as preferred background color, the functions assigns the RGB color 0xFFFFCDD2 to the screen. The first two hexadecimal symbols correspond to the Alpha channel value (transparency indicator with 00=transparent and FF=opaque), the other three pairs of symbols represent the contribution of RGB colors to the mix. The method setBackgroundColor applies the selected color to the app's layout.
6. The utility function saveStateData uses a SharedPreferenceFile container to keep the app's state data (just background color in this example). An Android SharedPreferenceFile is similar in structure and functionality to a Java
7. The utility method updateMeUsingSavedStateData is responsible for detecting the presence of the color key in the app's persistent preference file. In case the key "chosenBackgroundColor" is not found, the screen's background is painted using the default ("white") color. 3 . A p p l i c a t i o n ’ s L i f e c y c l e | 15
Appendix 3.1 Using Bundles to Save/Restore State Values
The following code snippet shows a common strategy to save and retrieve data from a Bundle. In the example, the key is called “STR_KEY” and its value is the string “blah blah blah”
@Override public void onCreate(Bundle savedInstanceState) { ... if ( savedInstanceState != null ) String someStrValue = savedInstanceState.getString("STR_KEY", "Default"); ... }
@Override public void onSaveInstanceState(Bundle outState) { ... outState.putString("STR_KEY", "blah blah blah"); onSaveInstanceState( outState ); ... }
Note: This approach works well when Android kills the app (like in a device-rotation event). However, it will not create the state bundle when the user kills the app (e.g., pressing BackButton). It is a better practice to save state using SharedPreferences in the onPause( ) method.
Appendix 3.2 Detecting Device Rotation
The function below allows you to obtain the current ORIENTATION of the device as NORTH(0), WEST(1), SOUTH(2) and EAST(3). private int getOrientation(){ // the TOP of the device points to [0:North, 1:West, 2:South, 3:East] Display display = ((WindowManager) getApplication() .getSystemService(Context.WINDOW_SERVICE)) .getDefaultDisplay(); display.getRotation(); return display.getRotation(); } Use the onCreate method to initialize a control variable with the original device’s orientation. During onPause compare the current orientation with its initial value. If the values are not the same, then the device was rotated.
int originalOrientation; //used to detect orientation change @Override protected void onCreate(Bundle savedInstanceState) { ... setContentView(R.layout.activity_main); originalOrientation = getOrientation(); ... } @Override 3 . A p p l i c a t i o n ’ s L i f e c y c l e | 16 protected void onPause() { super.onPause();
if( getOrientation() != originalOrientation ){ // Orientation changed - phone was rotated // put a flag in outBundle, call onSaveInstanceState(…) }else { // no orientation change detected in the session } }
Figure 3.8 Detecting Device Orientation in function of the device’s TOP position 3 . A p p l i c a t i o n ’ s L i f e c y c l e | 17