Version 2.2
Copyright © 2009, 2010, 2011, 2012 Lars Vogel
17.01.2012
| Revision History | ||
|---|---|---|
| Revision 0.1 | 20.07.2010 | Lars Vogel |
| Created | ||
| Revision 0.2 - 2.2 | 19.07.2010 - 20.01.2012 | Lars Vogel |
| bug fixes and enhancements | ||
Table of Contents
Intents
are asynchronous messages which allow Android components to
request
functionality from other components of the Android
system. For example
an
Activity
can send an
Intents
to the Android system which starts another
Activity.
Therefore
Intents
allow to combine loosely coupled components to perform certain
tasks.
Intents
can be used to signal to the Android system that a
certain
event has
occurred. Other components in Android can
register to this
event and
will get notified.
Intents
are instances of the
android.content.Intent
class.
Intents
are send to the Android system. Depending on how the
Intent
was constructed
the Android system will run an receiver determination
and determine what to do.
An
Intent
can also contain data. This data can be used by the receiving
component. For example your application can calls via an
Intent
a browser component. As data is it may send the URL to the browser
component.
Android supports explicit
and implicit
Intents.
Explicit
Intents
explicitly names the component which should be called by the Android
system, by using the Java class as identifier.
The following shows an explicit
Intent. If that
Intent
is correctly send to the Android system, it will start the associated
class.
Intent i = new Intent(this, ActivityTwo.class); i.putExtra("Value1", "This value one for ActivityTwo "); i.putExtra("Value2", "This value two ActivityTwo");
Explicit
Intents
are typically used within on application as the classes in an
application are controlled by the application developer.
Implicit
Intents
do not specify the Java class which should be called. They
specify the
action which should be
performed and optionally an URI
which
should
be
used for this
action.
For example the following tells the Android system to view a
webpage.
Typically the web browser is registered to this
Intent
but other component could also register themself to this event.
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.vogella.de"));
If
these
Intents
are send to the Android system it searches for all components which
are registered for the specific action and the data type.
If only one
component is found, Android starts this component
directly.
If several
components are identifier by the Android system,
the user
will get an
selection dialog and can decide which component
should be
used for
the
Intent.
An implicit
Intent
contains the Action and optional the URI. The receiving
component can
get this information via the
getAction()
and
getData()
methods.
Explicit and implicit
Intents
can also contain additional data. This data call be filled by the
component
which
creates the
Intent. It can
and can get extracted by the component which
receives the
Intent.
The component which creates the
Intent
can add data to it via the overloaded
putExtra()
method. Extras are key/value pairs; the key is always a String. As
value you can use the primitive data types (int, float,..), String,
Bundle, Parceable and Serializable.
For example you can trigger all components which have been
registered
to send some data via the
new Intent(Intent.ACTION_SEND)
This
Intent
determines possible receivers via the type. What is send it defined
via the
putExtra
method.
Intent sharingIntent = new Intent(Intent.ACTION_SEND); sharingIntent.setType("text/plain"); sharingIntent.putExtra(android.content.Intent.EXTRA_TEXT, "News for you!"); // createChooser is a convenience method to create // an Chooser Intent with a Title startActivity(Intent.createChooser(sharingIntent,"Share this using"));
The component which receives the
Intent
can
use the
getIntent().getExtras()
method call to get the extra data.
Bundle extras = getIntent().getExtras(); if (extras == null) { return; } String value1 = extras.getString("Value1"); String value2 = extras.getString("Value2"); if (value1 != null && value2 != null) { // Do something with the data }
If you send an
Intent
to the Android system, Android requires that you tell it to which
type of component your
Intent
should be send.
To start an
Activity
use the method
startActivity(Intent). This method is defined on the
Context
object and available in every
Activity
object.
If you call an
Activity
with the
startActivity(Intent)
method the caller requires no result from the called
Activity.
If you need
some information from the called
Activity
use the
startActivityForResult()
method.
public void onClick(View view) { Intent i = new Intent(this, ActivityTwo.class); i.putExtra("Value1", "This value one for ActivityTwo "); i.putExtra("Value2", "This value two ActivityTwo"); // Set the request code to any code you like, you can identify the // callback via this code startActivityForResult(i, REQUEST_CODE); }
If you use the
startActivityForResult()
method then the started
Activity
is called a
Sub-Activity.
If the Sub-Activity is finished it can send data back to its caller
via
Intent. This is done in the
finish()
method.
@Override public void finish() { // Prepare data intent Intent data = new Intent(); data.putExtra("returnKey1", "Swinging on a star. "); data.putExtra("returnKey2", "You could be better then you are. "); // Activity finished ok, return the data setResult(RESULT_OK, data); super.finish(); }
Once the
Sub-Activity
finished, the
onActivityResult()
method in the calling
Activity
will be called.
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == RESULT_OK && requestCode == REQUEST_CODE) { if (data.hasExtra("returnKey1")) { Toast.makeText(this, data.getExtras().getString("returnKey1"), Toast.LENGTH_SHORT).show(); } } }
If an
Intent
is send to the Android system, it will determine suitable
applications
for this
Intent. If several components have been registered for this type of
Intent, Android offers the user the choice to open
one of them.
This determination is based on
IntentFiltes. An
IntentFilter
specifies the types of
Intent
that an activity, service, or broadcast
receiver can respond to. An
IntentFilter
declares the capabilities of
a component. It specifies what what an
activity or service can do and what
types of broadcasts a
receiver can
handle. It allow the corresponding component to
receive
Intents
of the declared
type.
IntentFilters
are typically defined via the
"AndroidManifest.xml" file. For
BroadcastReceiver
it is also possible to define them in coding.
An
IntentFilters
is defined by its category, action
and data filters. It can also
contain additional metadata.
The following will register an
Activity
for the
Intent
which is triggered when someone wants to open a webpage.
<activity android:name=".BrowserActivitiy" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="http"/> </intent-filter> </activity>
If a component does not
define
Intent
filters, it can only be called by explicit
Intents.
As of Android 3.1 the Android system will per default exclude all
BroadcastReceiver
from receiving
Intents
if the corresponding application has never been started by the user
or if the user explicitly stopped the application via the Android
menu (in Manage Application).
This is an additional security features as the user can be sure that
only the applications he started will receive broadcast
Intents.
Intents
can also be used to send broadcast messages into the Android system.
BroadcastReceivers
can register to event and will get notified if such an event is
triggered.
Your application can register to system events, e.g. a new email has arrived, system boot is complete or a phone call is received and react accordingly.
As said earlier, since Android version 3.1 the Android system will per
default exclude all
BroadcastReceiver
from receiving
Intents
if the corresponding application has never been started by the user
or
if the user explicitly stopped the application via the Android
menu (in
Manage Application).
Sometimes you want to find if an application has registered for a certain intent. For example you want to check if a certain receiver is available and if you enable some functionality in your app.
This can be done via checking the PackageManager. The following code checks if an intent exists. You can check via this method for intent and change your application behavior accordingly for example disable or hide menu items.
public boolean isIntentAvailable(Context context, String action) { final PackageManager packageManager = context.getPackageManager(); final Intent intent = new Intent(action); List<ResolveInfo> resolveInfo = packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); if (resolveInfo.size() > 0) { return true; } return false; }
The following assumes that you have already basic knowledge in Android development. Please check the Android development tutorial to learn the basics.
The following tutorial demonstrates how to use explicit
Intents
and how to transfer data between
two
Activities.
The first
Activity
will call the second one via an explicit intent. Once the user select
the "Back" button on his phone the first
Activity
will receive some hard-coded data from the
Sub-Activity.
Create a new Android application
"de.vogella.android.intent.explicit"
with the
Activity
called
"ActivityOne".
Change the layout "main.xml" to the following.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:id="@+id/TextView01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:minHeight="60dip" android:text="First Activity. Press button to call second activity" android:textSize="20sp" > </TextView> <Button android:id="@+id/Button01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="onClick" android:text="Calling an intent" > </Button> </LinearLayout>
Create the layout "second.xml".
<?xml version="1.0" encoding="utf-8"?> <GridLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:alignmentMode="alignBounds" android:columnCount="2" android:columnOrderPreserved="false" android:useDefaultMargins="true" > <TextView android:layout_gravity="center_horizontal" android:text="Input 1" android:textSize="32dip" /> <EditText android:id="@+id/input1" android:layout_gravity="fill_horizontal" android:text="Default" /> <TextView android:layout_gravity="center_horizontal" android:text="Input 2" android:textSize="32dip" /> <EditText android:id="@+id/input2" android:layout_gravity="fill_horizontal" android:text="Default" /> <Button android:layout_column="1" android:layout_gravity="right" android:width="80dp" android:onClick="onClick" android:text="Finish" /> </GridLayout>
Declare a new
Activity
called "ActivityTwo" via the "AndroidManifest.xml" file.
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="de.vogella.android.intent.explicit" android:versionCode="1" android:versionName="1.0"> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".ActivityOne" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:label="ActivityTwo" android:name="ActivityTwo"></activity> </application> <uses-sdk android:minSdkVersion="9" /> </manifest>
Create the following coding for your two
Activities.
package de.vogella.android.intent.explicit; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.Toast; public class ActivityOne extends Activity { private static final int REQUEST_CODE = 10;/** Called when the activity is first created. */@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } public void onClick(View view) { Intent i = new Intent(this, ActivityTwo.class); i.putExtra("Value1", "This value one for ActivityTwo "); i.putExtra("Value2", "This value two ActivityTwo"); // Set the request code to any code you like, you can identify the // callback via this code startActivityForResult(i, REQUEST_CODE); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == RESULT_OK && requestCode == REQUEST_CODE) { if (data.hasExtra("returnKey1")) { Toast.makeText(this, data.getExtras().getString("returnKey1"), Toast.LENGTH_SHORT).show(); } } } }
package de.vogella.android.intent.explicit; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.EditText; public class ActivityTwo extends Activity {/** Called when the activity is first created. */@Override public void onCreate(Bundle bundle) { super.onCreate(bundle); setContentView(R.layout.second); Bundle extras = getIntent().getExtras(); if (extras == null) { return; } String value1 = extras.getString("Value1"); String value2 = extras.getString("Value2"); if (value1 != null && value2 != null) { EditText text1 = (EditText) findViewById(R.id.input1); EditText text2 = (EditText) findViewById(R.id.input2); text1.setText(value1); text2.setText(value2); } } public void onClick(View view) { finish(); } @Override public void finish() { Intent data = new Intent(); // Return some hard-coded values data.putExtra("returnKey1", "Swinging on a star. "); data.putExtra("returnKey2", "You could be better then you are. "); setResult(RESULT_OK, data); super.finish(); } }
Run your application. The first will send data to the second
Activity
which will be shown on the user interface. If you select back on your
phone, the first
Activity
will display a
Toast
with the data from the second
Activity.
The following tutorial demonstrates the usage of implicit
intents
of the Android System.
Create a new Android application "de.vogella.android.intent.implicit"
with a
Activity
called "
CallIntentsActivity
".
In this example we will use a
Spinner
to select the
Intent
which should get triggered. For the content of the
Spinner
we will define static values.
Create the following "intents.xml" file in the "res/values" folder.
<resources>
<string-array name="intents">
<item>Open Browser</item>
<item>Call Someone</item>
<item>Dial</item>
<item>Show Map</item>
<item>Search on Map</item>
<item>Take picture</item>
<item>Show contacts</item>
<item>Edit first contact</item>
</string-array>
</resources>
Change the layout file "main.xml" to the following.
<?xml version="1.0" encoding="utf-8"?> <GridLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:alignmentMode="alignBounds" android:columnCount="1" > <Spinner android:id="@+id/spinner" android:layout_gravity="fill_horizontal" android:drawSelectorOnTop="true" > </Spinner> <Button android:id="@+id/trigger" android:onClick="onClick" android:text="Trigger Intent"> </Button> </GridLayout>
To be able to use certain intents you need to register then for your application. Maintain the following "AndroidManifest.xml".
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="de.vogella.android.intent.implicit" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="15" /> <uses-permission android:name="android.permission.CALL_PRIVILEGED" > </uses-permission> <uses-permission android:name="android.permission.CALL_PHONE" > </uses-permission> <uses-permission android:name="android.permission.CAMERA" > </uses-permission> <uses-permission android:name="android.permission.READ_CONTACTS" > </uses-permission> <uses-permission android:name="android.permission.INTERNET"/> <application android:icon="@drawable/icon" android:label="@string/app_name" > <activity android:name=".CallIntentsActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
Change your activity to the following. We will start the new intent with the method startActivityForResult() which allow us to specify a desired result code. Once the intent is finished the method onActivityResult() is called and you can perform actions based on the result of the activity.
package de.vogella.android.intent.implicit; import android.app.Activity; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.view.View; import android.widget.ArrayAdapter; import android.widget.Spinner; import android.widget.Toast; public class CallIntentsActivity extends Activity { private Spinner spinner;/** Called when the activity is first created. */@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); spinner = (Spinner) findViewById(R.id.spinner); ArrayAdapter adapter = ArrayAdapter.createFromResource(this, R.array.intents, android.R.layout.simple_spinner_item); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spinner.setAdapter(adapter); } public void onClick(View view) { int position = spinner.getSelectedItemPosition(); Intent intent = null; switch (position) { case 0: intent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.vogella.de")); break; case 1: intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:(+49)12345789")); break; case 2: break; case 3: intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:(+49)12345789")); startActivity(intent); break; case 4: intent = new Intent(Intent.ACTION_VIEW, Uri.parse("geo:50.123,7.1434?z=19")); break; case 5: intent = new Intent(Intent.ACTION_VIEW, Uri.parse("geo:0,0?q=query")); break; case 6: intent = new Intent("android.media.action.IMAGE_CAPTURE"); break; case 7: intent = new Intent(Intent.ACTION_VIEW, Uri.parse("content://contacts/people/")); break; case 8: intent = new Intent(Intent.ACTION_EDIT, Uri.parse("content://contacts/people/1")); break; } if (intent != null) { startActivity(intent); } } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == Activity.RESULT_OK && requestCode == 0) { String result = data.toURI(); Toast.makeText(this, result, Toast.LENGTH_LONG); } } }
If you start your application you should see an list of buttons and if you press the button, different activities should be performed. Note that you didn't specify any receiving application only the thing that should be done.
The following example will register a
Activity
for the
Intent
which is triggered to view a http webpage.
Our application downloads the HTML source of this page and display
this
in a
TextView.
Create the
Android project
"de.vogella.android.intent. " with the
activity
"BrowserActivitiy".
Register your
Activity
to the
Intent
via the
Intent.Action_VIEW
action and the scheme "http" via the following "AndroidManifest.xml".
The manifest also declares the permission to access the
Internet.
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="de.vogella.android.intent.browserfilter" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="15" /> <uses-permission android:name="android.permission.INTERNET" > </uses-permission> <application android:icon="@drawable/icon" android:label="@string/app_name" > <activity android:name=".BrowserActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="http" /> </intent-filter> </activity> </application> </manifest>
Change "main.xml" to the following.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="@+id/textView"/> </LinearLayout>
Install your application. If you now trigger an Intent to open
an URL
your should be able to select your own component. You can for example
trigger this
Intent
via the example from the implicit tutorials.
package de.vogella.android.intent.browserfilter; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.URL; import android.app.Activity; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.os.StrictMode; import android.widget.TextView; public class BrowserActivity extends Activity {/** Called when the activity is first created. */@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // To keep this example simple, we allow network access // in the user interface thread StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder() .permitAll().build(); StrictMode.setThreadPolicy(policy); setContentView(R.layout.main); Intent intent = getIntent(); TextView text = (TextView) findViewById(R.id.textView); // To get the action of the intent use String action = intent.getAction(); if (action != Intent.ACTION_VIEW) { throw new RuntimeException("Should not happen"); } // To get the data use Uri data = intent.getData(); URL url; try { url = new URL(data.getScheme(), data.getHost(), data.getPath()); BufferedReader rd = new BufferedReader(new InputStreamReader( url.openStream())); String line = ""; while ((line = rd.readLine()) != null) { text.append(line); } } catch (Exception e) { e.printStackTrace(); } } }
If you select you component the HTML code should be loaded into your text view.


Before posting questions, please see the vogella FAQ. If you have questions or find an error in this article please use the www.vogella.de Google Group. I have created a short list how to create good questions which might also help you.
Eclipse RCP Training (German) Eclipse RCP Training with Lars Vogel
Android Tutorial Introduction to Android Programming
GWT Tutorial Program in Java and compile to JavaScript and HTML
Eclipse RCP Tutorial Create native applications in Java
JUnit Tutorial Test your application
Git Tutorial Put everything you have under distributed version control system