An Android application that is composed of several, simple activities tends to offer a much better user experience than one that has crammed all of its functionality into one, large and complex activity. A good rule of thumb is to try and limit every activity you create to just one indivisible task.
To get things done with such simple activities, however, you must create connections between activities and allow them to seamlessly exchange data with each other. In this tutorial, I show you how to use intents to create connections between activities and send data from one activity to another.
1. What Is an Intent?
In the real world, before you start performing an action, you usually intend to perform it. The same is true in the world of Android apps. To start an Android activity, you must have an intent for it.
Intents are instances of the Intent
class. They are such an integral part of the Android platform that even the simplest of apps need them. For example, consider the Hello World app you created earlier in this series. It is able to start when you touch its icon only because it is able to respond to an intent created by the launcher app on your device.
Along with details about the activity, an intent can contain additional data, aptly called extra data, to send arguments or return results from one activity to another.
2. Types of Intents
Intents can either be explicit or implicit. An intent is said to be explicit when you initialize it using the class literal of the activity you want to start. In case of implicit intents, you only specify the action you wish to perform and let the Android operating system determine the exact activity that should be started.
Usually, explicit intents are used to start activities that belong to your own application while implicit intents are meant for activities that belong to other apps installed on the user's device.
3. Creating an Explicit Intent
To create an explicit intent, you can use the setClass()
method of an Intent
object and pass the class literal of an activity to it, along with a reference to your current activity as the context. For example, if your current activity is MainActivity
and you want to create an intent to start an activity called OtherActivity
, you would use the following code:
Intent intent = new Intent(); intent.setClass(MainActivity.this, OtherActivity.class);
If you want to create an explicit intent for an activity that does not belong to your app, you use the setComponent()
method instead. As an argument, you must pass a ComponentName
object, which has been initialized using the package name of the required app and the fully qualified class name of the required activity.
For example, here's how you would create an intent for an activity called OtherActivity
that belongs to an app whose package name is com.example.otherapp:
Intent intent = new Intent(); intent.setComponent( new ComponentName("com.example.otherapp", "com.example.otherapp.OtherActivity" ) );
4. Creating an Implicit Intent
To create an implicit intent, you must use the setAction()
method of an Intent
object and pass a string object to it. The string object specifies the name of the action you intend to perform. The Android SDK has several standard actions. For most of them, you are also required to use the setData()
method to specify the data the action should work with. The data must always be in the form of a Uri
object.
One of the most widely used standard actions is ACTION_VIEW
, which can be used to launch a variety of apps, such as the default browser, the dialer, and the contacts app. For example, here's how you create an implicit intent to dial the number 123456789:
Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); // Generate a valid URI for the telephone number // using the Uri.parse method and pass it to setData intent.setData(Uri.parse("tel:123456789"));
By simply changing the Uri
object you pass to the setData()
method, you can change the app ACTION_VIEW
opens. For example, if you want to launch the browser and open the website https://tutsplus.com/ on it, the setData()
call would have to look like this:
intent.setData(Uri.parse("https://tutsplus.com"));
5. Adding Extras to an Intent
Some intents must contain additional data for them to work correctly. This additional data is called an extra. An extra is nothing but a key-value pair that belongs to a Bundle
object. Using a Bundle
is like using a HashMap
with two limitations:
- the keys must always be
String
objects - the values must always be primitives or
Parcelable
objects
Extras can be used with both implicit and explicit intents. To add an extra to an Intent
object, you can use the putExtra()
method. For example, here's how you can add an extra with key message and value Hello:
intent.putExtra("message", "Hello");
6. Using an Intent
Now that you understand how to create an intent and add data and extras to it, let's move on to actually using Intent
objects to start activities. The simplest way to start an activity using an Intent
object is to pass it as an argument to the startActivity()
method.
startActivity(intent);
The startActivity()
method is generally used only when you want to switch from one activity to another. In other words, startActivity()
helps you take the user from one screen of your app to another.
If you want to start an activity to perform a specific task and get the result of the task back, you must use the startActivityForResult()
method instead. This method, besides the Intent
object, also expects an integer that you use to identify the result of the activity. The integer is referred to as a request code.
Additionally, to be able to receive the result of an activity started using the startActivityForResult()
method, your activity must override the onActivityResult()
method. For example, the following code snippet shows you how to create an implicit intent to capture a photo using the device's default camera app and get a thumbnail of the captured photo as a result:
// An integer to identify the result of the // camera app's activity final static int CAMERA_RESULT_REQUEST_CODE = 1; private void takePhoto() { Intent intent = new Intent(); // Use ACTION_IMAGE_CAPTURE to refer to the // default camera app's activity intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE); // Launch the activity, and specify that // you expect a result whose request // code is equal to CAMERA_RESULT_REQUEST_CODE startActivityForResult(intent, CAMERA_RESULT_REQUEST_CODE); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent result) { // Check if requestCode matches the request // code passed to the startActivityForResult method. // Also check if the result is valid using the // resultCode parameter if(requestCode == CAMERA_RESULT_REQUEST_CODE && resultCode == RESULT_OK) { Bitmap thumbnail = (Bitmap)result.getExtras().get("data"); } }
Note that the result of an activity is also an Intent
object. In the above code snippet, I first used the getExtras()
method to fetch the Bundle
containing the extras that belong to the result. Next, I used the get()
method to fetch the thumbnail as a Bitmap
object.
7. Using Intent Filters
In the previous steps, you saw how to use implicit intents to start activities that belong to other apps installed on a user's device. You might now be wondering if other apps can start an activity that belongs to your app using the same procedure. The answer to that question is "not unless you want them to." By default, for security reasons, an activity cannot be started by activities that belong to other apps.
To expose an activity to other apps, you must create an intent filter for it. To do so, you must add an intent-filter
tag for it in the project's AndroidManifest.xml file.
For example, if you want an activity called MyCustomActivity
to respond to a custom action named my.custom.action, its entry in the manifest has to look like this:
<activity android:name=".MyCustomActivity"><intent-filter><action android:name="my.custom.action"/><category android:name="android.intent.category.DEFAULT" /></intent-filter></activity>
Note that, along with the action
tag specifying the action's name, the intent-filter
tag must also contain a category
tag whose name
attribute is set to android.intent.category.DEFAULT. Without the category
tag, your activity will not be able to respond to implicit intents.
With the intent filter we just created, any app is able to start MyCustomActivity
using the following code:
Intent intent = new Intent(); // The string passed to the setAction method // must match the action name mentioned in the // intent filter intent.setAction("my.custom.action"); startActivity(intent);
If you prefer not to use intent filters, but still want to expose an activity to other apps, you can add an exported
attribute to the activity's definition in the manifest, setting its value to true
.
<activity android:name=".MyCustomActivity" android:exported="true"/>
In this case, other apps have no choice but to use explicit intents to start the activity.
Conclusion
You now know how to connect any two activities present on a user's device using implicit and explicit intents. With this knowledge, you can start creating complex apps that have several screens. You can also easily reuse functionality already present in other apps installed on the user's device.
To learn more about intents, you can refer to the official documentation.