Download Mobile Application Frameworks and Services

Document related concepts
no text concepts found
Transcript
Mobile Application
Frameworks and Services
Lecture: Android Applications and Data
Management
Dr. Panayiotis Alefragis
Professor of Applications
Masters Science Program:
Technologies and Infrastructures for Broadband Applications and Services
1
Anatomy of Android Applications
Core Components
Core components are the primordial classes or building blocks from which
apps are made.
An Android application consists of one or more core component objects.
Components work in a cooperative mode, each contributing somehow to the
completion of the tasks undertaken by the app.
Each core component provides a particular type of functionality and has a
distinct lifecycle. A lifecycle defines how the component is created,
transitioned, and destroyed.
There are four type of core components
1. An Activity
2. A Service
3. A broadcast receiver
4. A content provider
Android's Core Components
1. Activity Class
• An Activity object is similar to a WindowsForm. It usually presents a single
graphical visual interface (GUI) which in addition to the displaying/coMecting
of data, provides some kind of 'code-behind' functionality.
• A typical Android application contains one or more Activity objects.
• Applications must designate one activity as their main task or entry point.
That activty is the first to be executed when the app is launched.
• An activity may transfer control and data to another activity through an
interprocess communication protocol called intents.
• For example, a login activity may show a screen to enter user name and
password. After clicking a button some authentication process is applied on
the data, and before the login activity ends some other activity is called.
Android's Core Components
2. Service Class
• Services are a special type activity that do not have a visual user interface.
A service object may be active without the user noticing its presence.
• Services are analogous to secondary threads, usually running some kind of
background 'busy-work' for an indefinite period of time.
• Applications start their own services or connect to services already active.
• Examples:
Your background GPS service could be set to quietly run in the backgroud
detecting location information from satellites, phone towers or wi-fi routers. The
service could periodically broadcast location coordinates to any app listening
for that kind of data. An application may opt for binding to the running GPS
service and use the data that it supplies.
3-5
Android's Core Components
2. Service
Background
Foreground
PANDORA
GPS
In this example a music service (say Pandora Radio) and GPS location run in the background. The
selected music station is heard while other GUIs are show on the device's screen. For instance, our
user -an avid golfer- may switch between occasional golf course data reading (using the GolfShot
app) and "Angry Birds" (some of his playing partners could be very slow).
Android's Core Components
3. 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, earth-quakes in California, speedcamera nearby.
• Broadcast receivers do not display a user interface.
• They tipically 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.
3. Broadcast Receiver
Broadcast Receiver
Foreground Activity
Method()
Waiting. My filter
Work to be done
after receiving an
ORANGE
message
only accepts
ORANGE signals.
Ignoring all others.
3-8
Android's Core Components
4. Content Provider Class
• A content provider is a data-centric service that makes persistent datasets
available to 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 an 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-9
4. Content Provider Class
User Application
query(...)
\r
«
insert(...)
«delete(...)
V
>
I
update(...)
A Content Provider is a wrapper that hides the actual physical data. Users
interact with their data through a common object interface. 3 - 10
Component's Life Cycle
Life and Death in Android
• Each Android application runs inside its own instance of a Dalvik
Virtual Machine (DVM).
• At any point in time several parallel DVM instances could be active
(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:
1. Number and age of the application's components currently running,
2. relative importance of those components to the user, and
3. how much free memory is available in the system.
Component's Life Cycle
Life and Death in Android
All components execute according to a master plan that consists of:
1. A beginning - responding to a request to instantiate them
2. An end - when the instances are destroyed.
3.
A sequence of in-between states - components sometimes are active or
inactive, or in the case of activities - visible or invisible.
Life as an Android Application:
Start
Active / Inactive
Visible / Invisible
End
Component's Life Cycle
The Activity Stack
• Activities in the 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 WBM 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 'next' any entry currently in the stack (more on this issue later)
Virtual buttons (Android 4.x):
Back, Home, Recent apps
Component's Life Cycle
3 - 14
Component's Life Cycle
Life Cycle Callbacks
When progressing from one state to the other, the OS notifies the
application of the changes by issuing calls to the following protected
transition methods:
void onCreate( )
void onStart( )
void onRestart( )
void onResume( )
void onPause( )
void onStop( )
void onDestroy( )
Life Cycle Callbacks
Most of your
code goes here
->
Save your
important
data here
public class ExampleActivity 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 (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.
}
}
Reference:
http://developer.android.com/reference/android/app/Activity.html
3 - 16
Life Cycle:
Activity States and Callback Methods
An activity has essentially
three phases:
1. It is active or running
2. It is paused or
3. It is stopped .
Moving from one state to the
other is accomplished by
means of the callback
methods listed on the edges
of the diagram.
3 - 17
Component's Life Cycle
Activity State: RUNNING
1. It is active or running when it is in the foreground of the screen (at
the top of the activity stack).
This is the activity that has "focus" and its graphical interface is
responsive to the user's interactions.
3 - 18
Component's Life Cycle
Activity State: PAUSED
2. It is paused if it has lost focus but is still visible to the user.
That is, another activity seats on top of it and that new activity either is
transparent or doesn't cover the full screen.
A paused activity is alive (maintaining its state information and attachment to
the window manager).
Paused activities can be killed by the system when available memory
becomes extremely low.
3 - 19
Component's Life Cycle
Activity State: STOPPED
3. It is stopped if it is completely obscured by another activity.
Continues to retain all its state information.
It is no longer visible to the user ( its window is hidden and its life cycle could
be terminated at any point by the system if the resources that it holds are
needed elsewhere).
3 - 20
Activity Life Cycle
Reference:
http://developer.android.com/training/basics/activitv-lifecvcle/starting.html
Application's Life Cycle
Foreground Lifetime
• An activity begins its lifecycle when it enters the onCreate() state.
• If it is not interrupted or dismissed, the activity performs its job and finally
terminates and releases resources when reaching the onDestroy() event.
3 - 27
Application's Life Cycle
Associating Lifecycle Events with Application's Code
Applications do not need to implement each of the transition methods,
however there are mandatory and recommended states to consider
(Mandatory)
onCreate() must be implemented by each activity to do its initial setup. The
method is executed only once on the activity's lifetime.
(Highly Recommended)
onPause() should be implemented whenever the application has some
important data to be committed so it could be reused.
3 - 28
Application's Life Cycle
Associating Lifecycle Events with Application's Code
onCreate()
• This is the first callback method to be executed when an
activity is created.
• Most of your application's code is written here.
• Typically used to initialize the application's data structures,
wire-up UI view elements (buttons, text boxes, lists) with local
Java controls, define listeners' behavior, etc.
• It may receive a data Bundle object containing the activity’s
previous state (if any).
Followed by onStart() —— onResume()....
3 - 29
Application's Life Cycle
Associating Lifecycle Events with Application's Code
onPause()
1. Called when the system is about to transfer control to
another activity. It should be used to safely write
uncommitted data and stop any work in progress.
2. The next activity waits until completion of this state.
3. Followed either by onResume() if the activity returns
back to the foreground, or by onStop() if it becomes
invisible to the user.
4. A paused activity could be killed by the system.
3 - 30
Application's Life Cycle
Killable States
• Android OS may terminate a killable app whenever the resources needed to
run other operation 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 be given a chance to
complete before the process is terminated.
• You should use onPause()to write any pending persistent data.
3 - 31
Application's Life Cycle
Data Persistence using Android SharedPreferences Class
• SharedPreferences is a simple Android persistence mechanism used to
store and retrieve <key,value> pairs, where key is a string and value is a
primitive data type (int, float, string...).
• This container class reproduces the structure and behavior of a Java
HashMap, however; unlike HashMaps it is persistent.
• Appropriate for storing small amounts of state data across sessions.
SharedPreferences myPrefSettings =
getSharedPreferences(MyPreferrenceFile, actMode);
Persistence is an important concept in Android, and it is discussed in more
detail latter.
3 - 32
Application's Life Cycle
Data Persistence using Android SharedPreferences Class
SharedPreference files
are permanently
stored in the application's process space.
Use DDMS file explorer to locate the entry:
data/data/your-package-name/sharedprefs
f
^Threads @ Heap @ Allocation Tracker
•?* Netwc
Name
Size Da-
acct
2D1
t> Qii!? cache
201
t> & config
201
g]
201
a data
^
201
tH? dTir
201
> & app
201
& app-asec
201
& app-lib
201
& app-private
201
& backup
201
bug reports
201
[_ Hnluj^cache
201
A I23> data
201
TS com.android.backupconfirm
201
Key Value
K l^a, mm snHrniH KmiA/cpr
.A csu.matoE.lifecycle
2013-09-06
11:35
drwxr-x--:;
t> Q3>cache
2013-09-05
14:17
drwxrwx--x
& lib
2013-09-06
11:35
Irwxrwxrwx -> /data/a..
a £57 shared_prefs
2013-09-06
11:54
drwxrwx:--x
130 2013-09-06
11:54
-rw-rw— ^
2013-09-03
13:39
drwxr-K--K
2013-09-03
ini3_no_n3
13::36
dn/irar-K--rl m/vni/v. _ _
^ U) myPrefFilel.xm.l
■ & jp.co.omronsott.openwnn
[>
25? dontpanic
K.
2zi_ rJ rmn
)
1
3 - 33
Application's Life Cycle
A complete Example: The LifeCycle App
The following application demonstrates the transitioning of a simple activity
through the Android's sequence of Life-Cycle states.
1. A Toast-msg will be displayed showing the current event's name.
2. An EditText box is provided for the user to indicate a background color.
3. When the activity is paused the selected background color value is saved
to a SharedPreferences container.
4. When the application is re-executed the last choice of background color
should be applied.
5. An EXIT button should be provide to terminate the app.
6. You are asked to observe the sequence of messages displayed when the
application:
1. Loads for the first time
2. Is paused after clicking HOME button
3. Is re-executed from launch-pad
4. Is terminated by pressing BACK and its own EXIT button
5. Re-executed after a background color is set
-3
-
34
Application's Life Cycle
Example: The LifeCycle App - Code: MainActivity.java pp.1
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tooLs"
android:id="@+id/myScreenl"
android:layout_width="fiLL_parent"
android:layout_height="fiLL_parent"
android:orientation="verticaL"
tools:context=".MainActivity" >
<EditText
android:id="@+id/editText1" android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Pick background (red, green, blue, white) 1 android:ems="10"
>
<requestFocus />
</EditText>
<Button
android:id="@+id/button1" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:text="Exit" />
<TextView
android:id="@+id/textView1" android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=" spy box - try clicking HOME and BACK" /> </LinearLayout>
3 - 35
Application's Life Cycle
Example: The LifeCycle App - Code: MainActivity.java pp.2
package csu.matos.lifecycle;
import java.util.Locale;
. . . //other libraries omitted for brevity
public class MainActivity extends Activity {
//class variables
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 PREFNAME = "myPrefFile1";
@Override
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
//display the main screen
setContentView(R.layout.activity_main);
//wiring GUI controls and matching Java objects
txtColorSelected = (EditText)findViewById(R.id.editTextl); btnExit = (Button)
findViewById(R.id.buttonl); txtSpyBox = (TextView)findViewById(R.id.textViewl); myScreen =
(LinearLayout)findViewById(R.id.myScreenl);
3 - 36
Application's Life Cycle
Example: The LifeCycle App - Code: MainActivity.java pp.3
//set GUI listeners, watchers,...
btnExit.setOnClickListener(new 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) {
//set background to selected color
String chosenColor = s.toString().toLowerCase(Locale.US);
txtSpyBox.setText(chosenColor);
setBackgroundColor(chosenColor, myScreen);
}
});
3 - 37
Application's Life Cycle
Example: The LifeCycle App - Code: MainActivity.java pp.4
//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();
Application's Life Cycle
Example: The LifeCycle App - Code: MainActivity.java pp.5
@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();
}
@Override
protected void onStop() { super.onStop();
Toast.makeText(context, "onStop", duration).show();
}
Example: The LifeCycle App – Code
MainActivity.java pp.6
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(0xffff0000); //Color.RED if (chosenColor.contains("green"))
myScreen.setBackgroundColor(0xff00ff00); //Color.GREEN if (chosenColor.contains("blue"))
myScreen.setBackgroundColor(0xff0000ff); //Color.BLUE if (chosenColor.contains("white"))
myScreen.setBackgroundColor(0xffffffff); //Color.BLUE } //setBackgroundColor
private void saveStateData(String chosenColor) {
//this is a little <key,value> table permanently kept in memory
SharedPreferences myPrefContainer = getSharedPreferences(PREFNAME,
Activity.MODE_PRIVATE); //pair <key,value> to be stored represents our 'important' data
SharedPreferences.Editor myPrefEditor = myPrefContainer.edit();
String key = "chosenBackgroundColor";
String value = txtSpyBox.getText().toString(); myPrefEditor.putString(key, value); myPrefEditor.commit();
}//saveStateData
3 - 40
Application's Life Cycle
Example: The LifeCycle App - Code: MainActivity.java pp.7
private void updateMeUsingSavedStateData() {
// (in case it exists) use saved data telling backg color
SharedPreferences myPrefContainer =
getSharedPreferences(PREFNAME, Activity.MODE_PRIVATE);
String key = "chosenBackgroundColor";
String defaultValue = "white";
if (( myPrefContainer != null ) &&
myPrefContainer.contains(key)){
String color = myPrefContainer.getString(key, defaultValue);
setBackgroundColor(color, myScreen);
}
} //updateMeUsingSavedStateData
} //Activity
3 - 41
Example: The LifeCycle App - Code: MainActivity.java pp.8
3 - 42
Example: The LifeCycle App - Code: MainActivity.java
pp.9
“ll I 5:53
3 - 43
Example: The LifeCycle App - Code: MainActivity.java pp.10
*4\ ! 6:28
C\Cookie
LifeCycle
User selects a green
background and clicks Exit.
When the app is paused the
user's selection is saved and
the app finally terminates.
The app is re-executed
Saved state information defining
background color is reused by the
new app's instance. Life cycle begins
on the onCreate state
3 - 44
Example: The LifeCycle App - Code: MainActivity.java pp.11
The app is re-started and becomes
visible again, showing all the state
values previously set by the user
(see the text boxes)
User selects a green
background and clicks the
HOME key. When the app is
paused the user's selection is
saved, the app is still active
but it is not visible.
3 - 45
Application's Life Cycle
Questions?
Appendix A: Using Bundles to Save/Restore State Values
@Override
public void onCreate(Bundle savedInstanceState) {
• ••
String someStrValue = savedInstanceState.getString("STR_KEY");
}
@Override
public void onPause() {
Bundle myBundle = new Bundle();
myBundle.putString("STR_KEY", "blah blah blah");
}
onSaveInstanceState( myBundle );
3 - 46
Application's Life Cycle
Questions?
Appendix A: Using Bundles to Save/Restore State Values
@Override
public void onCreate(Bundle savedInstanceState) {
• ••
if (savedInstanceState != null ) {
strVar = savedInstanceState.getString("STR_KEY");
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
outState.putString("STR_KEY", "blah-blah-blah" );
super.onSaveInstanceState(outState);
}
3 - 47
Appendix B: Detecting Device Rotation
1
of
2
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();
}
^ North: 0
top
West: 1
—
>
top
South: 2 ^
3 - 48
Appendix B: Detecting Device Rotation
2
of
2
Use the onCreate method to initialize a control variable with the original
device's orientation. During onPause compare the current orientation with its
original value; if they 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
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
}
}
3 - 49
Android Applications Lifecycle
Wrap-Up
Android Programming Components
• Activity
– http://developer.android.com/guide/topics/fundamentals/activities.html
• Service
– http://developer.android.com/guide/topics/fundamentals/services.html
• Content Providers
• Broadcast Receivers
• Android in a nutshell:
– http://developer.android.com/guide/topics/fundamentals.html
Activities (1)
• The basis of android applications
• A single Activity defines a single viewable screen
– the actions, not the layout
• Can have multiple per application
• Each is a separate entity
• They have a structured life cycle
– Different events in their life happen either via the user touching
buttons or programmatically
Activities (2)
Services (1)
• Run in the background
– Can continue even if Activity that started it dies
– Should be used if something needs to be done while the user is not
interacting with application
• Otherwise, a thread is probably more applicable
– Should create a new thread in the service to do work in, since the
service runs in the main thread
• Can be bound to an application
– In which case will terminate when all applications bound to it unbind
– Allows multiple applications to communicate with it via a common
interface
• Needs to be declared in manifest file
• Like Activities, has a structured life cycle
Services (2)
Intents, Intent Filters,
and Invoking Activities:
Part I: Using Class Name
Originals of Slides and Source Code for Examples:
http://www.coreservlets.com/android-tutorial/
Idea
• Android philosophy
– Activities are small, single-screen units
• Consequence
– You need easy way to switch from one Activity to another
• Approach: use Intent
– An abstract description of an operation to be performed
– Intent can refer to class name of Activity or a URI
– If a URI, then Activity registers as handler for the scheme, host
name, or MIME type of the URI
– In all cases, new Activity must have entry in AndroidManifest.xml
in order to be invoked
58
Summary of Options
• Invoke Activity by class name (Part I)
– Exactly one Activity can match
– New Activity must be in same project as original
– Can send data via an “extras” Bundle
• Invoke Activity by URI (Part II)
– More than one Activity could match
– New Activity need not be in the same project as original
– Can send data via URI parameters or “extras” Bundle
• Switch Activities via tabs (Not covered)
– Can use class name or URI to specify Activity
– New Activity must be in same project as original
– Can send data via URI parameters or “extras” Bundle
59
Example Target Activity:
Loan Payment Calculator
Example Target Activity:
Loan Calculator
• Inputs
– Loan amount
– Interest rate (as a percent)
– Loan period in months
• Outputs
– Monthly payment
– Total payments over life of loan
• Both
are
in
same
(e.g., dollars) as the loan amount
units
• Defaults
– Unless values are passed in from other
Activity, uses default values for all inputs
61
Summary of Layout
Entries in first column
are right-aligned.
Entries in second column are
left-aligned. They are also
given ids so that the Java
code can insert the text.
This is a View with
android:column_span="2"
and a fixed height.
TableLayout
62
XML: Layout File: First Row
(res/layout/loan_payment.xml)
<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://..."
android:layout_width="match_parent"
android:layout_height="match_parent"
android:stretchColumns="1">
<TableRow android:layout_marginTop="20dp">
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/default_foreground"
android:textSize="@dimen/font_size"
android:text="@string/loan_amount_prompt"
android:gravity="right"/>
<TextView android:id="@+id/loan_amount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/default_foreground"
android:textSize="@dimen/font_size"
android:gravity="left"/>
</TableRow>
Second and third rows are very similar. Bottom two rows are almost the same except for a different textColor for the second column.
63
XML: Layout File: Divider
(res/layout/loan_payment.xml)
<TableRow>
<TextView android:layout_span="2"
android:layout_width="match_parent"
android:layout_height="5dp"
android:background="@color/divider_background"/>
</TableRow>
64
XML: Strings File
(res/values/strings.xml)
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Intent Filters and Activity Switching</string>
<string name="loan_calculator_app_name">
Loan Calculator: Monthly Payments
</string>
<string name="tabs_app_name">Tabbed Windows</string>
<string name="loan_amount_prompt">Loan amount:&#160;&#160;</string>
<string name="interest_rate_prompt">Interest rate:&#160;&#160;</string>
<string name="loan_period_prompt">Months:&#160;&#160;</string>
<string
name="monthly_payment_prompt">Monthly
payment:&#160;&#160;</string>
<string
name="total_payments_prompt">Total
payments:&#160;&#160;</string>
</resources>
The same prompts will also be used in a later input form.
Note that &#160; represents a non-breaking space. Regular spaces are not preserved at the beginning and end of strings in Android
resource files. Note also that &nbsp; is not legal here, since that is a character entity specific to HTML, not general in XML.
65
XML: Colors File
(res/values/colors.xml)
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Used inside loan_payments.xml. -->
<color name="default_foreground">#d3d3d3</color>
<color name="divider_background">#ffffff</color>
<color name="result_foreground">#ff0000</color>
</resources>
66
XML: Dimensions File
(res/values/dimensions.xml)
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="font_size">20dp</dimen>
</resources>
If you haven't seen a dimensions file before, note that the file name is arbitrary, as with all of
the resource files in res/values. However, dimensions.xml is a common convention. Since they
come with units (dp, sp, px, in, mm), you cannot store dimensions as regular strings.
Dimensions are supplied via "@dimen/some_name" to attributes that expect font sizes,
margin sizes, widths, heights, etc. In this case, "@dimen/font_size" was supplied for the
android:textSize attribute of each of the TextViews.
67
Java (LoanCalculatorActivity.java)
public class LoanCalculatorActivity extends Activity {
private double mLoanAmount=100000,
mAnnualInterestRateInPercent=5.0;
private long mLoanPeriodInMonths=360; // 30 years
private String mCurrencySymbol = "$";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.loan_payments);
setInputsFromExtras();
setInputsFromUri();
calculateAndSetOutputValues();
}
We will explain setInputsFromExtras in an upcoming subsection. We will
explain setInputsfromUri in Part II of the Intents series. For now, these
methods make no changes to the instance variables, and the default values of
the instance variables (shown at the top) will be used by
calculateAndSetOutputValues.
68
Java, Continued (LoanCalculatorActivity.java)
private void calculateAndSetOutputValues() {
PaymentInfo paymentInfo =
new PaymentInfo(mLoanAmount, mAnnualInterestRateInPercent,
mLoanPeriodInMonths, mCurrencySymbol);
TextView loanAmountDisplay = (TextView)findViewById(R.id.loan_amount);
loanAmountDisplay.setText(paymentInfo.getFormattedLoanAmount());
TextView interestRateDisplay =
(TextView)findViewById(R.id.interest_rate);
interestRateDisplay.setText
(paymentInfo.getFormattedAnnualInterestRateInPercent());
TextView loanPeriodDisplay = (TextView)findViewById(R.id.loan_period);
loanPeriodDisplay.setText(paymentInfo.getFormattedLoanPeriodInMonths());
TextView monthlyPaymentDisplay =
(TextView)findViewById(R.id.monthly_payment);
monthlyPaymentDisplay.setText(paymentInfo.getFormattedMonthlyPayment());
TextView totalPaymentsDisplay =
(TextView)findViewById(R.id.total_payments);
totalPaymentsDisplay.setText(paymentInfo.getFormattedTotalPayments());
}
The math is done in the PaymentInfo class (next slides) at the top of the
method, which in turn calls the LoanUtils class (following slides). The rest
of the code just assigns the output values to the TextViews that are in the
second column of the table from the layout file
(res/layouts/loan_payments.xml).
69
Java (PaymentInfo.java)
public class PaymentInfo {
private final double mLoanAmount, mAnnualInterestRateInPercent,
mMonthlyPayment, mTotalPayments;
private final long mLoanPeriodInMonths;
private final String mCurrencySymbol;
public PaymentInfo(double loanAmount,
double annualInterestRateInPercent,
long loanPeriodInMonths, String currencySymbol) {
mLoanAmount = loanAmount;
mAnnualInterestRateInPercent = annualInterestRateInPercent;
mLoanPeriodInMonths = loanPeriodInMonths;
mCurrencySymbol = currencySymbol;
mMonthlyPayment = LoanUtils.monthlyPayment(loanAmount,
annualInterestRateInPercent,
loanPeriodInMonths);
mTotalPayments = mMonthlyPayment * mLoanPeriodInMonths;
}
...
}
The remaining methods are just getter methods and variations of the getter
methods that return the values as formatted strings (e.g., with commas and with
exactly two values after the decimal point).
70
Java (LoanUtils.java)
public class LoanUtils {
public static double monthlyPayment(double loanAmount,
double annualInterestRateInPercent,
long loanPeriodInMonths) {
if (annualInterestRateInPercent <= 0) {
annualInterestRateInPercent = 0.0000001;
}
double monthlyInterestRate = annualInterestRateInPercent / 1200.0;
double numerator = loanAmount * monthlyInterestRate;
double denominator = 1 –
Math.pow(1 + monthlyInterestRate,
-1 * loanPeriodInMonths);
return (numerator / denominator);
}
}
Formula taken from
http://www.financeformulas.net/Loan_Payment_Formula.html and
http://en.wikipedia.org/wiki/Mortgage_calculator#Monthly_payment_formula
71
Example: Results
For now, these values are fixed to the initial
values set for the instance variables of the
LoanCalculatorActivity. However, the
upcoming sections will show how to pass
values from another Activity to this one.
Computed by LoanUtils.
Formatted by PaymentInfo.
72
Invoking Activities by
Class Name
Summary
• Idea
– Specify class name of new Activity
• New Activity must be in same project as original Activity
• Syntax
– Java (original Activity)
Intent activityIntent = new Intent(this, NewActivity.class);
startActivity(activityIntent);
– XML (AndroidManifest.xml)
<activity android:name=".NewActivity"
android:label="@string/some_app_name">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category
android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
74
Example:
Invoking Loan Calculator
with Default Values
Example: Overview
• Initial Activity
– Has
Button
that,
when
invokes the loan calculator activity
pressed,
• No data is sent to the loan calculator,
so it will use default values for the
loan amount, interest rate, etc.
• Approach
– Create
Intent
referring
LoanCalculatorActivity.class
to
• Thus, the two Activities must be in same
project
– Call startActivity
– Put entry for LoanCalculatorActivity in
AndroidManifest.xml
• So that the initial Activity has permission to
invoke the loan calculator
76
XML: Layout File
(res/layout/main.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://..."
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button android:text="Calculate Loan Payments
Data)"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:onClick="showLoanPayments1"/>
...
</LinearLayout>
Other buttons shown later
77
(No
XML: Manifest File Template
(AndroidManifest.xml)
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.coreservlets.intentfilter1"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="8" />
<application android:icon="@drawable/icon"
android:label="@string/app_name">
This part is generated
<activity android:name=".IntentFilter1Activity"
automatically when you build a
new Android project in Eclipse.
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
Means that this is
...
the Action that runs
</application>
when you run the
Other Activities will be
</manifest>
Means that this app
project.
declared here.
See next slide for
LoanCalculatorActivity.
gets an icon on the
screen of your
Android device.
78
XML: Manifest File
Action Declaration
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.coreservlets.intentfilter1"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="8" />
<application android:icon="@drawable/icon"
Use the fully-qualified name if the new Activity is in
a different package than the main one (i.e., the
android:label="@string/app_name">
one listed at the top in the "manifest" start tag).
... <!-- Declaration for IntentFilter1Activity on previous slide -->
<activity android:name=".LoanCalculatorActivity"
android:label="@string/loan_calculator_app_name">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
... <!-- "data" entry shown later; not used in this example -->
</intent-filter>
</activity>
Means that this
Means that this
Action displays data
...
Action can be the
to the user, but is not
</application>
default for certain
launched as the initial
types of data (shown
Activity of the project.
</manifest>
later).
The "data" tag of the land the "activity" tag for the
tabbed windows Activity are both shown later.
You virtually always set action.VIEW and category.DEFAULT
for Activities that will be invoked by other Activities.
79
XML: Strings File
(res/values/strings.xml)
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">
Intent Filters and Activity Switching
</string>
...
</resources>
Other strings shown earlier, and apply to the LoanCalculatorActivity, not to the initial Activity with the buttons that launch the loan calculator.
80
Java (IntentFilter1Activity.java)
public class IntentFilter1Activity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
public void showLoanPayments1(View clickedButton) {
Intent activityIntent =
new Intent(this, LoanCalculatorActivity.class);
startActivity(activityIntent);
}
...
}
Event handler methods for other buttons shown later
81
Example: Results
82
Sending Data via the
“Extras” Bundle
Summary
• Idea
– Attach a Bundle (like a Map – see next slides) to the Intent. The
Bundle will contain data to be used by the new Activity.
• Syntax
– Java (original Activity)
Intent
activityIntent
=
new
Intent(this,
NewActivity.class);
Bundle newActivityInfo = new Bundle();
newActivityInfo.putBlah(…); // putDouble, putString, etc.
activityIntent.putExtras(newActivityInfo);
startActivity(activityIntent);
– Java (new Activity)
Intent intent = getIntent();
Bundle info = intent.getExtras();
if (info != null) { /* Retrieve vals with info.getBlah(...) */ }
84
The Bundle Class: Details
• Putting data in a Bundle
– putBoolean, putBooleanArray, putDouble, putDoubleArray,
putString, putStringArray, putStringArrayList etc.
• These
all
take
keys
and
values
as
arguments.
The keys must be Strings. The values must be of the standard types
(int, double, etc.) or array of them.
– You can also make a custom class that implements Serializable or
Parceleable, then store instance of that class with putSerializable or
putParceleable
• Methods return void, so you cannot chain as with the putExtra method
of Intent.
• Retrieving data from a Bundle
– getBoolean,
getBooleanArray,
getDouble,
getString, getStringArray, getStringArrayList, etc.
• These
take
keys
(Strings)
No typecast required on retrieval.
getDoubleArray,
as
arguments.
85
Option 1: Attaching Entire Bundle to Intent
• Idea
– Make a Bundle, add it all at once to Intent.
• Instantiate a Bundle, then use the Bundle’s putBlah method (one such
method for each standard type). Then, attach Bundle to Intent with
Intent’s putExtras method.
• Syntax
Bundle newActivityInfo = new Bundle();
newActivityInfo.putDouble("key1", someDouble);
newActivityInfo.putString("key2", someString);
…
yourIntent.putExtras(newActivityInfo);
– Note that it is putExtras, not putExtra
86
Option 2: Adding One Piece of Data at a Time
to Intent
• Idea
– Add individual pieces of data to the Intent. No need to explicitly
create and attach a Bundle.
• You use the overloaded “putExtra” method. The first argument is the
key (String), and the second argument is the value, which can be of any
standard type. However, the code that retrieves the value later needs
to know type.
• Syntax
yourIntent.putExtra("key1", someDouble);
yourIntent.putExtra("key2", someString);
…
– Unlike putBlah for Bundle, these putExtra methods return the Intent, so
you can do jQuery-like chaining:
» yourIntent.putExtra(…).putExtra(…) … .putExtra(…);
87
Example:
Invoking Loan Calculator
with Custom Values
Example: Overview
• Initial Activity
– Has
Button
that,
when
invokes the loan calculator activity
pressed,
• Creates
randomized
data
sends it to the loan calculator,
retrieves the values and uses
for its calculations.
and
which
them
• Approach
– Create
Intent
referring
LoanCalculatorActivity.class
– Create Bundle with 3 values
to
• Loan amount, interest rate, loan period
– Attach Bundle to Intent with putExtras
– Call startActivity
– Put entry for LoanCalculatorActivity
manifest
in
89
XML: Layout File
(res/layout/main.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://..."
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
...
<Button
android:text="Calculate Loan Payments (with Data)"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:onClick="showLoanPayments2"/>
...
First button shown earlier
</LinearLayout>
90
XML: Manifest File
Action Declaration
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.coreservlets.intentfilter1"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="8" />
<application android:icon="@drawable/icon"
android:label="@string/app_name">
... <!-- Declaration for IntentFilter1Activity on previous slide -->
<activity android:name=".LoanCalculatorActivity"
android:label="@string/loan_calculator_app_name">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
... <!-- "data" entry shown later; not used in this example -->
</intent-filter>
</activity>
...
</application>
</manifest>
No changes from previous example.
91
Java (IntentFilter1Activity.java)
public class IntentFilter1Activity extends Activity {
...
public void showLoanPayments2(View clickedButton) {
Intent activityIntent =
new Intent(this, LoanCalculatorActivity.class);
activityIntent.
putExtras(LoanBundler.makeRandomizedLoanInfoBundle());
startActivity(activityIntent);
}
...
}
Code for onCreate and first button’s event handler shown earlier.
92
Java (LoanBundler.java)
public class LoanBundler {
public static Bundle makeLoanInfoBundle(double loanAmount,
double
annualInterestRateInPercent,
long loanPeriodInMonths,
String currencySymbol) {
Bundle loanInfo = new Bundle();
loanInfo.putDouble("loanAmount", loanAmount);
loanInfo.putDouble("annualInterestRateInPercent",
annualInterestRateInPercent);
loanInfo.putLong("loanPeriodInMonths", loanPeriodInMonths);
loanInfo.putString("currencySymbol", currencySymbol);
return(loanInfo);
}
93
Java
(LoanBundler.java, Continued)
public static Bundle makeRandomizedLoanInfoBundle() {
Random randomizer = new Random();
double loanAmount = 25000 * (1 + randomizer.nextInt(10));
double interestRate = 0.25 * (1 + randomizer.nextInt(60));
long loanPeriod = 12 * (1 + randomizer.nextInt(30));
return(LoanBundler.makeLoanInfoBundle(loanAmount,
interestRate,
loanPeriod));
}
94
Java (LoanCalculatorActivity.java)
public class LoanCalculatorActivity extends Activity {
private double mLoanAmount=100000,
mAnnualInterestRateInPercent=5.0;
private long mLoanPeriodInMonths=360; // 30 years
private String mCurrencySymbol = "$";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.loan_payments);
setInputsFromExtras();
setInputsFromUri();
calculateAndSetOutputValues();
}
95
Java (LoanCalculatorActivity, Continued)
private void setInputsFromExtras() {
Intent intent = getIntent();
Bundle loanInfo = intent.getExtras();
if (loanInfo != null) {
double loanAmount = loanInfo.getDouble("loanAmount");
double annualInterestRateInPercent =
loanInfo.getDouble("annualInterestRateInPercent");
long loanPeriodInMonths =
loanInfo.getLong("loanPeriodInMonths");
String currencySymbol =
loanInfo.getString("currencySymbol");
setInputs(loanAmount, annualInterestRateInPercent,
loanPeriodInMonths, currencySymbol);
}
}
96
Java (LoanCalculatorActivity, Continued)
private void setInputs(double loanAmount,
double annualInterestRateInPercent,
long loanPeriodInMonths,
String currencySymbol) {
if (loanAmount > 0) {
mLoanAmount = loanAmount;
}
if (annualInterestRateInPercent > 0) {
mAnnualInterestRateInPercent =
annualInterestRateInPercent;
}
if (loanPeriodInMonths > 0) {
mLoanPeriodInMonths = loanPeriodInMonths;
}
if (currencySymbol != null) {
mCurrencySymbol = currencySymbol;
}
}
97
Example: Results
98
Wrap-Up
More Reading
• Tutorial: Intents and Intent Filters
– http://developer.android.com/guide/topics/intents/
intents-filters.html
• JavaDoc: Intent
– http://developer.android.com/reference/android/content/
Intent.html
• Chapters:
Creating
Intent
Filters
Launching Activities and Sub-Activities
and
– From The Busy Coder’s Guide to Android Development
• http://commonsware.com/Android/
• Chapter: Intents and Services
– From Android in Action by Ableson et al
100
Summary
• Java (original Activity)
Intent activityIntent = new Intent(this, NewActivity.class);
Bundle newActivityInfo = new Bundle();
newActivityInfo.putBlah(…); // putDouble, putString, etc.
activityIntent.putExtras(newActivityInfo);
startActivity(activityIntent);
• Java (new Activity)
Intent intent = getIntent();
Bundle info = intent.getExtras();
if (info != null) { /* Retrieve vals with info.getBlah(...) */ }
• XML (AndroidManifest.xml)
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
101
Intents, Intent Filters,
and Invoking Activities:
Part II: Using URI
Topics in This Section
• Part I
– Invoking Activities by class name
– Defining dimensions in res/values
– Sending data via the “extras” Bundle
• Part II
– Invoking Activities with a URI
– Sending data via parameters in the URI
• Part III
– Invoking Activities with tabbed windows
– Defining two-image icons in res/drawable
103
Overview
Summary of Options
• Invoke Activity by class name (Part I)
– Exactly one Activity can match
– New Activity must be in same project as original
– Can send data via an “extras” Bundle
• Invoke Activity by URI (Part II)
– More than one Activity could match
– New Activity need not be in the same project as original
– Can send data via URI parameters or “extras” Bundle
• Switch Activities via tabs (Part III)
– Can use class name or URI to specify Activity
– New Activity must be in same project as original
– Can send data via URI parameters or “extras” Bundle
105
Invoking Activities
with a URI
Summary
•
Idea
– Supply a URI that indirectly refers to new Activity. The new Activity registers as
target for URIs of a certain form.
• The originating Activity and the new Activity need not be in the same project
• More than one Activity could match the URI.
– If so, Android will ask you which one to use.
•
Syntax
– Java (original Activity)
Uri uri = Uri.parse("foo://bar.example.com/baz");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(activityIntent);
– XML (AndroidManifest.xml)
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="foo" android:host="bar.example.com" />
</intent-filter>
107
Registering to Handle URIs
• Matching the URI itself
– Register for a scheme and a host
• Example URI
– loan://coreservlets.com/calc
• intent-filter entry
– <data android:scheme="loan" android:host="coreservlets.com" />
– Note that the “calc” part is arbitrary – just to make URL look better.
• Matching the data type
– Register for a MIME type
• Example URIs
– content:// (referring to that MIME type)
– file:// (referring to that MIME type)
– anything:// (the Intent can call setType to specify MIME type)
• intent-filter entry
– <data android:mimeType="some/type" />
– <data android:mimeType="something/*" />
108
Predefined Action/URI
Combinations
Action
URI
Meaning
Intent.ACTION_CALL
tel:phone_number
Opens phone application and calls
phone_number.
Intent.ACTION_DIAL
tel:phone_number
Opens phone application and dials
(but doesn’t call) phone_number.
Intent.ACTION_DIAL
voicemail:
Opens phone application and dials
(but doesn’t call) the voice mail
number.
Intent.ACTION_VIEW
geo:lat,long
Opens the maps application centered
on (lat, long).
Intent.ACTION_VIEW
geo:0,0?q=address
Opens the maps application centered
on the specified address.
Intent.ACTION_VIEW
http://url
https://url
Opens the browser application to the
specified address.
Intent.
ACTION_WEB_SEARCH
109
plain_text
Opens the browser application and
uses Google search for given string.
Table adapted from Section 4.1.5 of Android in Action by Ableson et al.
Example:
Invoking Loan Calculator
(Data in Extras Bundle)
Example: Overview
• Initial Activity
– Has
Button
that,
invokes the loan calculator activity
when
pressed,
• Initial Activity uses URI to indirectly invoke loan calculator
• Initial Activity is in different project than loan calculator
• Data is sent via extras Bundle as in previous example
• Approach
– Create Intent with Intent.ACTION_VIEW
"loan://coreservlets.com/calc“
and
URI
• The “calc” at the end is arbitrary – just for aesthetics
– Create and attach Bundle as in previous example
– Call startActivity
– Put data entry for LoanCalculatorActivity in manifest
– <data android:scheme="loan" android:host="coreservlets.com" />
111
of
XML: Layout File
(res/layout/main.xml – 2nd Proj.)
<?xml version="1.0" encoding="utf-8"?>
<TableLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:stretchColumns="1">
<TableRow>
<Button
android:text="Calculate Loan Payments (Data in Extras)"
android:layout_span="2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="showLoanPayments1"/>
</TableRow>
...
</TableLayout>
Entries for input form and
second button shown later.
112
XML: Manifest File
Action Declaration (Loan Proj.)
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.coreservlets.intentfilter1"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="8" />
<application android:icon="@drawable/icon"
android:label="@string/app_name">
... <!-- Declaration for IntentFilter1Activity shown earlier -->
<activity android:name=".LoanCalculatorActivity"
android:label="@string/loan_calculator_app_name">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="loan" android:host="coreservlets.com"
/>
</intent-filter>
</activity>
...
</application>
</manifest>
113
Java (IntentFilter2Activity.java)
public class IntentFilter2Activity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
public void showLoanPayments1(View clickedButton) {
Uri uri = Uri.parse("loan://coreservlets.com/calc");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
intent.putExtras
(LoanBundler.makeRandomizedLoanInfoBundle());
startActivity(intent);
}
...
}
Code for second button (that embeds data in the URI) shown later.
114
Java Code Shown Earlier
• LoanBundler
– Makes a Bundle that stores the loan amount, interest rate, and loan
period
• LoanCalculatorActivity
– Calls getIntent().getExtras() and reads the data out of the resultant
Bundle. Uses that for the initial values for the loan amount, interest
rate, and loan period
– Passes the values to PaymentInfo, which in turn uses LoanUtils to
calculate monthly payment and total payments
– Puts all five values (loan amount, interest rate, loan period, monthly
payment, total payments) into TextViews
115
Example: Results
116
Sending Data via
Parameters in the URI
Summary
• Idea
– Embed query parameters in the URI. These parameters will represent
data to be used by the new Activity.
• Syntax
– Java (original Activity)
String address =
"loan://coreservlets.com/calc?loanAmount=xxx&…";
Uri uri = Uri.parse(address);
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(activityIntent);
– Java (new Activity)
Uri uri = getIntent().getData();
String loanAmountString = uri.getQueryParameter("loanAmount");
// Convert String to double
...
118
Sending Data:
Extras vs. URI Parameters
• Extras Bundle
– Pros
• Can send data of different types.
• No parsing required in Activity that receives the data.
– Cons
• More complex for originating Activity
– Requires parsing in originating Activity if values come from EditText
• URI parameters
– Pros
• Simpler for originating Activity, especially if EditText used
• More consistent with URI usage
– Cons
• Can send Strings only
• Requires parsing in receiving Activity
119
Example:
Invoking Loan Calculator
(Data in URI Parameters)
Example: Overview
• Initial Activity
– Has
Button
that,
invokes the loan calculator activity
when
pressed,
• Data is extracted from textfields (EditTexts) and embedded in the URI
that is used to invoke loan calculator
• Approach
– Create Intent with Intent.ACTION_VIEW
"loan://coreservlets.com/calc?data"
and
URI
• Data is
"loanAmount=…&annualInterestRateInPercent=…&…"
– Call startActivity
– Put data entry for LoanCalculatorActivity in manifest
– <data android:scheme="loan" android:host="coreservlets.com" />
121
of
XML: Layout File
(res/layout/main.xml – 2nd Proj.)
<?xml version="1.0" encoding="utf-8"?>
<TableLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:stretchColumns="1">
...
<TableRow android:layout_marginTop="30dp">
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/loan_amount_prompt"
android:gravity="right"/>
<EditText android:id="@+id/loan_amount"
android:inputType="numberDecimal"
android:layout_height="wrap_content">
<requestFocus></requestFocus>
</EditText>
</TableRow>
...
Entry for first button shown earlier. Entries for other textfields
</TableLayout>
(EditTexts) similar to the one shown. Entry for button at the bottom just
has android:onClick="showLoanPayments2".
122
XML: Strings File
(res/values/strings.xml)
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Intent Filters and Activity Switching</string>
<string name="loan_calculator_app_name">
Loan Calculator: Monthly Payments
</string>
<string name="tabs_app_name">Tabbed Windows</string>
<string name="loan_amount_prompt">Loan amount:&#160;&#160;</string>
<string name="interest_rate_prompt">Interest rate:&#160;&#160;</string>
<string name="loan_period_prompt">Months:&#160;&#160;</string>
<string
name="monthly_payment_prompt">Monthly
payment:&#160;&#160;</string>
<string
name="total_payments_prompt">Total
payments:&#160;&#160;</string>
</resources>
The same prompts are also used in the output display.
Note that &#160; represents a non-breaking space. Regular spaces are not preserved at the beginning and end of strings in Android
resource files. Note also that &nbsp; is not legal here, since that is a character entity specific to HTML, not general in XML.
123
XML: Manifest File
Action Declaration (Loan Proj.)
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.coreservlets.intentfilter1"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="8" />
<application android:icon="@drawable/icon"
android:label="@string/app_name">
... <!-- Declaration for IntentFilter1Activity shown earlier -->
<activity android:name=".LoanCalculatorActivity"
android:label="@string/loan_calculator_app_name">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="loan" android:host="coreservlets.com"
/>
</intent-filter>
</activity>
...
</application>
Unchanged from previous example.
</manifest>
124
Java (IntentFilter2Activity.java)
public class IntentFilter2Activity extends Activity {
...
public void showLoanPayments2(View clickedButton) {
String address =
makeLoanAddressFromEditTextInputs();
Uri uri = Uri.parse(address);
Intent intent =
new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
}
Code for onCreate and first button shown earlier.
125
Java
(IntentFilter2Activity, Continued)
private String makeLoanAddressFromEditTextInputs() {
EditText loanAmountInput = (EditText)findViewById(R.id.loan_amount);
Editable loanAmount = loanAmountInput.getText();
String loanAmountParam =
String.format("loanAmount=%s", loanAmount);
EditText interestRateInput = (EditText)findViewById(R.id.interest_rate);
Editable interestRate = interestRateInput.getText();
String interestRateParam =
String.format("annualInterestRateInPercent=%s", interestRate);
EditText loanPeriodInput = (EditText)findViewById(R.id.loan_period);
Editable loanPeriod = loanPeriodInput.getText();
String loanPeriodParam =
String.format("loanPeriodInMonths=%s", loanPeriod);
String baseAddress = "loan://coreservlets.com/calc";
String address =
String.format("%s?%s&%s&%s", baseAddress, loanAmountParam,
interestRateParam, loanPeriodParam);
return(address);
}
126
Java (LoanCalculatorActivity.java)
public class LoanCalculatorActivity extends Activity {
private double mLoanAmount=100000,
mAnnualInterestRateInPercent=5.0;
private long mLoanPeriodInMonths=360; // 30 years
private String mCurrencySymbol = "$";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.loan_payments);
setInputsFromExtras();
setInputsFromUri();
calculateAndSetOutputValues();
}
127
Java (LoanCalculatorActivity, Continued)
private void setInputsFromUri() {
Uri uri = getIntent().getData();
if (uri != null) {
double loanAmount = getDoubleParam(uri, "loanAmount");
double annualInterestRateInPercent =
getDoubleParam(uri, "annualInterestRateInPercent");
long loanPeriodInMonths =
getLongParam(uri, "loanPeriodInMonths");
String currencySymbol =
uri.getQueryParameter("currencySymbol");
setInputs(loanAmount, annualInterestRateInPercent,
loanPeriodInMonths, currencySymbol);
}
}
getQueryParameter is the builtin method of Uri. getDoubleParam and getLongParam (next slides) are
methods of LoanCalculatorActivity that call getQueryParameter and then parse the resultant String.
128
Java (LoanCalculatorActivity, Continued)
private void setInputsFromUri() {
Uri uri = getIntent().getData();
if (uri != null) {
double loanAmount = getDoubleParam(uri, "loanAmount");
double annualInterestRateInPercent =
getDoubleParam(uri, "annualInterestRateInPercent");
long loanPeriodInMonths =
getLongParam(uri, "loanPeriodInMonths");
String currencySymbol =
uri.getQueryParameter("currencySymbol");
setInputs(loanAmount, annualInterestRateInPercent,
loanPeriodInMonths, currencySymbol);
}
}
129
Java (LoanCalculatorActivity, Continued)
private double getDoubleParam(Uri uri, String queryParamName) {
String rawValue = uri.getQueryParameter(queryParamName);
double value = 0.0;
try {
value = Double.parseDouble(rawValue);
} catch(Exception e) { } // NumberFormatEx or NullPointerEx
return(value);
}
private long getLongParam(Uri uri, String queryParamName) {
String rawValue = uri.getQueryParameter(queryParamName);
long value = 0;
try {
value = Long.parseLong(rawValue);
} catch(Exception e) { } // NFE or NPE
return(value);
}
130
Example: Results
131
Wrap-Up
Summary
• Java (original Activity)
String address =
"loan://coreservlets.com/calc?loanAmount=xxx&…";
Uri uri = Uri.parse(address);
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(activityIntent);
• Java (new Activity – can be different project)
Uri uri = getIntent().getData();
String loanAmountString = uri.getQueryParameter("loanAmount");
// Convert String to double, handle bad data
...
• XML (AndroidManifest.xml)
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="loan" android:host="coreservlets.com" />
</intent-filter>
133
Android Intents
Appendix A. Built-In Intent Actions
A complete list of built-in, broadcast, service actions, categories, and features for a
particular SDK can be found in the folders: .../android-sdk/platforms/platformYYY/data/
android.app.action.
ACTION_PASSWORD_CHANGED
ACTION_PASSWORD_EXPIRING
ACTION_PASSWORD_FAILED
ACTION_PASSWORD_SUCCEEDED
ADD_DEVICE_ADMIN
DEVICE_ADMIN_DISABLE_REQUES
TED
DEVICE_ADMIN_DISABLED
DEVICE_ADMIN_ENABLED
SET_NEW_PASSWORD
START_ENCRYPTION
android.bluetooth.a2dp.profile.action.
CONNECTION_STATE_CHANGED
PLAYING_STATE_CHANGED
android.bluetooth.adapter.action.
CONNECTION_STATE_CHANGED
DISCOVERY_FINISHED DISCOVERY
STARTED
LOCAL_NAME_CHANGED
REQUEST_DISCOVERABLE
REQUEST_ENABLE
SCAN_MODE_CHANGED
STATE_CHANGED
android.bluetooth.device.action.
ACL_CONNECTED
ACL_DISCONNECT_REQUESTED
ACL_DISCONNECTED
BOND_STATE_CHANGED
CLASS_CHANGED
FOUND
NAME_CHANGED
UUID
android.bluetooth.devicepicker.action.
DEVICE_SELECTED
LAUNCH
82
Android Intents
Appendix A. Built-In Intent Actions cont. 1
android.bluetooth.headset.
action.VENDOR_SPECIFIC_HEADSET_EVENT
profile.action.AUDIO_STATE_CHANGED
profile.action.CONNECTION_STATE_CHANGED
android.hardware.action.
NEW_PICTURE
NEW_VIDEO
input.action.QUERY_KEYBOARD_LAYOUTS
android.intent.action.
ACTION_POWER_CONNECTED
ACTION_POWER_DISCONNECTED
ACTION_SHUTDOWN
AIRPLANE_MODE
ALL_APPS
ANSWER
APP_ERROR
ASSIST
ATTACH_DATA
BATTERY_CHANGED
BATTERY_LOW
BATTERY_OKAY
BOOT_COMPLETED
BUG_REPORT
CALL
CALL_BUTTON
CAMERA_BUTTON
CHOOSER
CONFIGURATION_CHANGED
CREATE_LIVE_FOLDER
CREATE_SHORTCUT
DATE_CHANGED
DELETE
DEVICE_STORAGE_LOW
DEVICE_STORAGE_OK
DIAL
DOCK_EVENT
DREAMING_STARTED
DREAMING_STOPPED
EDIT
83
Android Intents
Appendix A. Built-In Intent Actions cont. 2
android.intent.action.
EVENT_REMINDER
EXTERNAL_APPLICATIONS_AVAILAB
LE
EXTERNAL_APPLICATIONS_UNAVAIL
ABLE
FETCH_VOICEMAIL
GET_CONTENT
GTALK_CONNECTED
GTALK_DISCONNECTED
HEADSET_PLUG
INPUT_METHOD_CHANGED
INSERT
INSERT_OR_EDIT
INSTALL_PACKAGE
LOCALE_CHANGED
MAIN
MANAGE_NETWORK_USAGE
MANAGE_PACKAGE_STORAGE
MEDIA_BAD_REMOVAL
MEDIA_BUTTON
MEDIA CHECKING
MEDIA_EJECT
MEDIA_MOUNTED
MEDIA_NOFS
MEDIA_REMOVED
MEDIA_SCANNER_FINISH
ED
MEDIA_SCANNER_SCAN_
FILE
MEDIA_SCANNER_START
ED
MEDIA_SEARCH
MEDIA_SHARED
MEDIA_UNMOUNTABLE
MEDIA_UNMOUNTED
MUSIC_PLAYER
MY_PACKAGE_REPLACED
NEW_OUTGOING_CALL
NEW_VOICEMAIL
PACKAGE_ADDED
PACKAGE_CHANGED
PACKAGE_DATA_CLEARE
D
PACKAGE_FIRST_LAUNCH
PACKAGE FULLY
84
Android Intents
Appendix A. Built-In Intent Actions cont. 3
android.intent.action.
PACKAGE_INSTALL
PACKAGE_NEEDS_VERIFICA
TION
PACKAGE_REMOVED
PACKAGE_REPLACED
PACKAGE_RESTARTED
PACKAGE_VERIFIED
PASTE
PHONE_STATE
PICK
PICK_ACTIVITY
POWER_USAGE_SUMMARY
PROVIDER_CHANGED
PROXY_CHANGE
REBOOT
RESPOND_VIA_MESSAGE
RINGTONE_PICKER
RUN
SCREEN_OFF
SCREEN_ON
SEARCH
SEARCH_LONG_PRE
SS
SEND
SEND_MULTIPLE
SENDTO
SET_ALARM
SET_WALLPAPER
SYNC
SYSTEM_TUTORIAL
TIME_SET
TIME_TICK
TIMEZONE_CHANGE
D
UID_REMOVED
UNINSTALL_PACKAG
E
USER_PRESENT
VIEW
VOICE_COMMAND
WALLPAPER_CHANG
ED
WEB_SEARCH
85
Android Intents
Appendix A. Built-In Intent Actions cont. 4
android.media.
action.CLOSE_AUDIO_EFFECT_CONTROL_SE
SSION
action.DISPLAY_AUDIO_EFFECT_CONTROL_P
ANEL
action.OPEN_AUDIO_EFFECT_CONTROL_SE
SSION
ACTION_SCO_AUDIO_STATE_UPDATED
AUDIO_BECOMING_NOISY
RINGER_MODE_CHANGED
android.net.
SCO_AUDIO_STATE_CHANGED
conn.BACKGROUND_DATA_SETTING_CHAN
VIBRATE
SETTING CHANGED
GED
conn.CONNECTIVITY_CHANGE
nsd.STATE_CHANGED
wifi.action.REQUEST_SCAN_ALWAYS_AVAIL
ABLE
wifi.NETWORK_IDS_CHANGED
wifi.p2p.CONNECTION_STATE_CHANGE
wifi.p2p.DISCOVERY_STATE_CHANGE
wifi.p2p.PEERS_CHANGED
wifi.p2p.STATE_CHANGED
wifi.p2p.THIS_DEVICE_CHANGED
wifi.PICK_WIFI_NETWORK
wifi.RSSI_CHANGED
wifi.SCAN_RESULTS
wifi.STATE_CHANGE
wifi.supplicant.CONNECTION_CHAN
GE
wifi.supplicant.STATE_CHANGE
wifi.WIFI STATE CHANGED
android.nfc.action.
ADAPTER_STATE_CHAN
GED
NDEF_DISCOVERED
TAG_DISCOVERED TECH
DISCOVERED
86
Android Intents
Appendix A. Built-In Intent Actions cont. 5
android.settings.
ACCESSIBILITY_SETTINGS
ADD_ACCOUNT_SETTINGS
AIRPLANE_MODE_SETTINGS
APN_SETTINGS
APPLICATION_DETAILS_SETTINGS
APPLICATION_DEVELOPMENT_SETT
INGS
APPLICATION_SETTINGS
BLUETOOTH_SETTINGS
DATA_ROAMING_SETTINGS
DATE_SETTINGS
DEVICE_INFO_SETTINGS
DISPLAY_SETTINGS
DREAM_SETTINGS
INPUT_METHOD_SETTINGS
INPUT_METHOD_SUBTYPE_SETTIN
GS
INTERNAL_STORAGE_SETTINGS
LOCALE_SETTINGS
LOCATION_SOURCE_SETTINGS
MANAGE_ALL_APPLICATIONS_SETTI
NGS
MANAGE APPLICATIONS SETTINGS
MEMORY_CARD_SETTINGS
NETWORK_OPERATOR_SETTINGS
NFC_SETTINGS
NFCSHARING_SETTINGS
PRIVACY_SETTINGS
QUICK_LAUNCH_SETTINGS
SECURITY_SETTINGS
SETTINGS
SOUND_SETTINGS
SYNC_SETTINGS
USER_DICTIONARY_SETTINGS
WIFI_IP_SETTINGS
WIFI_SETTINGS
WIRELESS_SETTINGS
android.speech.tts.
engine.CHECK_TTS_DATA
engine.GET_SAMPLE_TEXT
engine.INSTALL_TTS_DATA
engine.TTS_DATA_INSTALLED
TTS_QUEUE_PROCESSING_COMPL
ETED
87
Ευχαριστώ για την προσοχή σας!