1. Introduction
There are four major components in Android, and three of them are related to intents, which shows how important intents are in the Android ecosystem. Intents are carriers of information, which can be used to request components to do corresponding operations. However, compared with this function, the structure of intents itself is worth studying.
By the end of this article you will know:
1. Display invocation of Intent and implicit invocation 2. Matching rules for implicit invocation 3. Usage scenarios of implicit invocation 4. Advantages of implicit invocation
2. Intent and component
Intent to promote the interaction between the components, this is very important for developers, and it also can as the carrier of message, to guide the component makes the corresponding behavior, that is the Intent can carry data, passed to the Activity/Service/BroadcastReceiver.
- Start the Activity. An Activity is simply a page on the screen of a phone. You can start an instance of an Activity, that is, a page, by passing the Intent to the startActivity method. At the same time, the Intent can carry data and pass it to the new Activity. If you want to get the result of a new Activity, you can start the Activity with the onActivityResult() method.
- To start the Service. A Service is a component that performs operations in the background without rendering an interaction screen. You can start a Service by passing an Intent through the startService() method.
- Transmit a BroadCast. Broadcast is a message that can be received by any application. You can transmit the broadcast to the receiver by passing the Intent to the sendBroadcast(), sendOrderedBroadcast(), or sendStickyBroadcast() method.
3. The type of Intent
Intents fall into two types:
- Intent displays the call;
- Intent an implicit call;
3.1 Intent Display invocation
This is the most common way to call a component, specifying the component information directly, including the package name and class name. The implicit invocation of intEnts is described in detail here.
3.2 Intent Implicit invocation
IntentFilter: IntentFilter: IntentFilter: IntentFilter: IntentFilter: IntentFilter: IntentFilter: IntentFilter: IntentFilter: IntentFilter Implicit call correlation is covered in a new section.
4. Functions and scenarios of implicit intents
4.1 The function of implicit IntEnts
Reduced coupling: In the era of componentization, components can be invoked implicitly without dependency. More secure: there is no need to specify component information and only components that match the specification will be invoked. More flexible: with a wider range of application scenarios, we can call many services provided by the system, such as making phone calls, sending SMS messages, etc.
4.2 Scenario where IntEnts are used implicitly
I believe many of you have done a phone demo, with the following code can be implemented.
Intent intent = new Intent(Intent.ACTION_DIAL); Uri data = uri.parse ("tel:" + "phone number "); intent.setData(data); startActivity(intent);Copy the code
This is a simple implicit invocation where we set the action and data of the Intent to match the corresponding component. (There is a matching rule, more on that later.)
Of course, there are many application scenarios: 1. Startup of components between different applications. 2. Interaction between lib and Module. And so on, can be applied to Intent implicit calls.
5. The Intent implicitly invokes the matching rule IntentFilter
We all know that implicit calls match components to start them, but how do they match? Let’s look at IntentFilter in more detail.
IntentFilter supports action, category, and Data filtering information.
Let’s start with a simple filtering rule
<activity android:name="SecondActivity"> <intent-filter> <action android:name="android.intent.action.Second"/> <category android:name="android.intent.category.DEFAULT"/> <data android:mimeType="image/*"/> </intent-filter> </activity>Copy the code
This is a simple Intent that can be launched using the following rules.
Intent intent = new Intent();
intent.setAction("android.intent.action.Second");
intent.addCategory("android.intent.category.DEFAULT");
intent.setDataAndType(Uri.parse("file://abc"),"image/png");
startActivity(intent); Copy the code
This lets you implicitly launch SecondActivity.
Now that we have a basic understanding of IntentFilter, let’s look at its matching rules in more detail.
5.1 Action Matching rules
Action is a string. The system defines some actions, such as making a phone call, etc. We can also customize the action. The action matching rule is that an intent filter can have multiple actions, so long as the action in the intent can match the same set of actions in the intent filter. Note that the intent does not specify an action, so the match fails. In addition, actions are case sensitive.
5.2 Category Matching Rule
So a category is a string, and the system defines a bunch of categories, and you can also customize them, and they match differently than an action, so if there are several categories in an intent, Each category must be defined in the intent filter. That is, an intent may not have any category. If it does, each category must be the same as any category defined in the Intent filter. Why we didn’t add android to the intent filter. The intent. The category. The DEFAULT this category would be an error? Reason is the system call startActivity or startActivityForResult will DEFAULT in intent with android. Intent. The category. The DEFAULT in this category.
5.3 Data Matching Rules
The matching rules for data are similar to those for actions. If an Intent filter defines data, it must also define a matching data; otherwise, the matching fails. First, let’s understand the structure of data. Data consists of two parts, mimeType and URI.
5.3.1 mimetype
MimeType refers to the media type, such as image/ JPEG, text/plain, and video/*. It can refer to different media formats such as pictures, texts, and videos.
5.3.2 URI
A URI consists of scheme, host, port, and path. Host and port together form the host:port (Authority) part
<scheme>://<host>:<port>/<path>Copy the code
1.Scheme: the URI mode, such as HTTP, file, and content. If Scheme is not specified, all other parameters of the URI are invalid, which means that the URI is invalid. 2.Host: the Host name of the URI, such as www.baidu.com. If Host is not specified, all other parameters of the URI are invalid, meaning that the URI is invalid. 3.Port: indicates the Port number of the URI, for example, 80. The Port parameter is valid only when scheme and host parameters are specified in the URI. 4.Path: indicates the Path.
Such as:
The content: / / 192.168.10.1:8080 / a fold/etcCopy the code
In this URI, Scheme is content, host is 192.168.10.1, port is 8080, and Path is Folder /etc. This is the format we usually use for web urls.
In a URI, each component is optional, but has linear dependencies
When URI matching is performed, the comparison is not complete, but partial. Here are the URI matching rules.
1. If only the scheme part of a URI is declared, all URIs with the same scheme will be matched, and other parts will not be matched
2. If a URI declares the Scheme and authority parts, the URI that has the same Scheme and authority can be matched successfully. The PATH part is not matched
3. If all parts of a URI are declared, only urIs that are identical in all parts will be matched successfully
5.3.3 Data Filtering Rules
After understanding the structure of data, the filtering rules of data will be introduced
- Case 1: The data rule is incomplete. As shown below.
<intent-filter>
<data android:mimeType="image/*"/>
</intent-filter>Copy the code
The mimeType attribute in an intent must be “image/*” in order for a match to succeed. In this case, although no URI is specified, the default schema for the URL part of the intent is content and file. The intent does not specify a URI, but the schema of the URI part of the intent must be content or file.
- Case 2: Multiple sets of data rules are defined, and each data has a full property defined, both URI and mimeType. As shown below.
<intent-filter>
<data android:mimeType="video/mpeg" android:scheme="http" ... />
<data android:mimeType="audio/mpeg" android:scheme="http" ... />
</intent-filter>
Copy the code
To match the intent filter, we also need to define a set of data rules in the intent to match successfully. In addition, to specify the full data for an intent, you must call setDataAndType. You cannot call setData first and then setType, because the two methods clear each other’s values. Finally, when we launch an Activity implicitly, we can make a judgment call to see if any Activity matches our intent to avoid unnecessary crashes. There are two ways to judge: one is to use the PackageManager resolveActivity method, the other is to use the Intent resolveActivity method, if they can not find a matching Activity will return null, according to its return value we avoid the above problem. First, let’s look at the source of the Intent’s resolveActivity method
public ComponentName resolveActivity(PackageManager pm) { if (mComponent ! = null) { return mComponent; } ResolveInfo info = pm.resolveActivity( this, PackageManager.MATCH_DEFAULT_ONLY); if (info ! = null) { return new ComponentName( info.activityInfo.applicationInfo.packageName, info.activityInfo.name); } return null; }Copy the code
From which we can see that its internal is also directly called PackageManager resolveActivity method to determine whether the match is successful. Let’s look at the PackageManager resolveActivity method again
public abstract ResolveInfo resolveActivity(Intent intent, int flags);Copy the code
The first parameter is the intent we parse. The second parameter uses the MATCH_DEFAULT_ONLY flag bit in the source code. This flag bit matches only activities that declare the category in the Intent filter. The point of using it is that startActivity must succeed as long as this method does not return NULL. Finally, an example:
Intent intent = new Intent(); intent.setAction("com.dev.test"); intent.setType("image/*"); ComponentName componentName = intent.resolveActivity(getPackageManager()); If (componentName == null) {// If null, toast.maketext (mainactivity.this, "Matching failed ", toast.length_short).show(); } else {// if not null, startActivity startActivity(intent); }Copy the code