Practical Android skills: communication between components-intent and intentfilter

Source: Internet
Author: User
Understanding intent and intentfilter -- Understanding intent and intentfilter

Intent (intent) is a very important component in Android. It is a bridge and link connecting different applications and also enables component-Level Reuse (activity and service) this may be an important reason. Intent is used in two ways: sending intent, and receiving intent is officially called intent resolving. This document introduces intent and intentfilter.
Intent and intentfilter are Android and message communication mechanisms that allow communication between system components. The carrier of information is intent, which can be an action request to be completed or a general message broadcast, which can be sent by any component. Messages, that is, intent, are finally processed and digested by components. A message is sent by a component. Generally, information about the target component is marked in the message. In addition, the target component also needs to tell the system which messages are of interest to the system, it needs to set some filters to filter out irrelevant messages.
In fact, it is like broadcasting in schools. Broadcasting sometimes broadcasts notifications, but sometimes plays the actions to be executed, such as cleaning. Messages usually indicate the target object of the message, which may be a computer school, a teacher, or an English talent. Everyone, or a college organization, only cares about the news related to them. Of course, they need to determine which messages are related to them by themselves. In Android, messages are intent, and filters are intentfilter. The component that sends a message can set the relevant information of the target component in the message, and the target component can also set a filter. Then, the system will filter and pass only the messages that the component is interested in to the component. Here, we assume that the reader has understood the basic usage of intent and intentfilter and will not give a full introduction. If you do not know about it, read the official documentation first, here we will focus on some precautions for using intentfilter.
There are two types of intent message mechanisms: explicit intent (explicit intent) and implicit intent (implicit intent ).

  • Explicit intent-specify the target component in intent, that is, specify the name of the target component (component name) in intent, and specify the complete package name and class name. Because it is difficult for you to know the component name of an application other than this program, explicit intent is usually used for internal communication within the application. More specifically, intent is used to start components inside the application, usually activity or service. No explicit intent has been used to send broadcasts to broadcastreceiver.
  • Implicit intent -- that is, the target component is not specified in the intent. The intent cannot contain the target name. The system searches for target components based on other information, such as data, type, and category.

Implicit intent is usually used to communicate with components outside the application. Application-level component reuse is mainly achieved by implicit intent. Intentfilter is only used by implicit intent. The explicit intent directly transmits the intent to the target component and does not care about the intentfilter of the component.

Explicit intent (explicit intent)

Display intent is easy to use. You only need to specify the name of the target component in intent, that is, set the Component Attribute through the intent method. As mentioned above, explicit intent is usually used to start activity or service in an application. In fact, it is not completely confined to the application. for external application activity and service, you can also use an explicit intent to start, but you must know their names.
You can set the component name by using the following methods:

public Intent setComponent(ComponentName component);public Intent setClass(Context packageContext, Class<?> cls);public Intent setClassName (Context packageContext, String className);public Intent setClassName (String packageName, String className);

In fact, although there are so many methods to set, the attribute of the intent internally identifies the target component only has one component. Therefore, the purpose of setting this method is to set the component of the target component, in fact, there are so many methods because the componentname structure is overloaded. When parsing intent, the system also obtains this Component Attribute and starts it.
Componentname intent. getcomponent ();
When an application starts an activity, intent is usually set as follows:

       Intent i = new Intent();       // Select one of them       i.setComponent(new ComponentName(getApplication(), ViewStubDemoActivity.class));       i.setComponent(new ComponentName(getApplication(), ViewStubDemoActivity.class.getName()));       i.setComponent(new ComponentName(getApplication().getPackageName(), ViewStubDemoActivity.class.getName()));       i.setClass(getApplication(), ViewStubDemoActivity.class);       i.setClassName(getApplication(), ViewStubDemoActivity.class.getName());       i.setClassName(getApplication().getPackageName(), ViewStubDemoActivity.class.getName());       startActivity(i);

Because the component classes in the application can be accessed, you must write as few string constants as possible to reduce spelling errors. If you must use the package name and class name, pay attention to it, the class name must be the full name, that is, starting from the package name, such as "com. hilton. networks. wifimanageractivity ".
However, for external application activities, you can only use the following methods:

       Intent i = new Intent();       // select one of them       i.setComponent(new ComponentName("com.hilton.networks", "com.hilton.networks.WifiManagerActivity"));       i.setClassName("com.hilton.networks", "com.hilton.networks.WifiManagerActivity");       startActivity(i);

First, the context parameter cannot be enough, because you cannot get the context of other applications. You can only get the context of your application, therefore, using the context of your application to start an external activity will certainly report an error. Second, you can use class. getname () to specify the class name as above. You cannot import external classes, and compilation errors may occur. In addition, be sure not to spell an error. Otherwise, a runtimeexception will be thrown.
The same applies to service components. Intent is written in the same way as activity components, but explicit intent is usually used for broadcastreceiver components.
Message filter of implicit intent -- intentfilter

Intentfilter is used to parse the implicit intent (implicit intent), that is, to tell the system which implicit intent can be processed by your components (activity, service, broadcastreceiver. We usually use the following methods:

<manifest ...>    <receiver ...>           <intent-filter>              <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />              <action android:name="android.appwidget.action.APPWIDGET_ENABLED" />              <action android:name="android.appwidget.action.APPWIDGET_DISABLED" />              <action android:name="android.appwidget.action.APPWIDGET_DELETED" />           </intent-filter>           <intent-filter>              <action android:name="android.intent.action.MEDIA_MOUNTED"/>              <action android:name="android.intent.action.MEDIA_UNMOUNTED"/>              <action android:name="android.intent.action.MEDIA_SHARED"/>              <action android:name="android.intent.action.MEDIA_REMOVED"/>              <action android:name="android.intent.action.MEDIA_EJECT"/>              <data android:scheme="file" />           </intent-filter>           <intent-filter>              <action android:name="android.intent.action.PACKAGE_ADDED"/>              <action android:name="android.intent.action.PACKAGE_REMOVED"/>              <action android:name="android.intent.action.PACKAGE_DATA_CLEARED"/>              <data android:scheme="package" />           </intent-filter>   </receiver></manifest>

When using intentfilter in manifest, pay attention to the following three points:
1. Pay attention to spelling mistakes
Note that the action and data string constants in intentfilter should not be written incorrectly because they will not be checked during compilation, no exception will be thrown during running. If you make a spelling mistake, such as case spelling, there will be no errors during compilation and running, but your program will not work properly, your program cannot receive the corresponding intent. A colleague wrote some actions in intentfilter, but misspelled one of them. It took him one afternoon to debug the results, finally, another colleague found a spelling mistake in Case sensitivity only when chatting with him.
Here we can also find that the intentfilter of Android in the manifest file is poorly encapsulated. If, only if, these Action constants can be written by reference, you can check and match them during compilation, greatly reducing the chance of errors, it also enhances encapsulation and information hiding. For example, the preceding code can be written as follows:

<manifest ...>    <receiver ...>           <intent-filter>              <action android:name="@android:action/AppWidgetManager.APPWIDGET_UPDATE" />              <action android:name="@android:action/AppWidgetManager.APPWIDGET_ENABLED" />              <action android:name="@android:action/AppWidgetManager.APPWIDGET_DISABLED" />              <action android:name="@android:action/AppWidgetManager.APPWIDGET_DELETED" />           </intent-filter>   </receiver></manifest>

Although this kind of spelling mistake is very low-level, when the program cannot work properly, no one will think of it as a spelling mistake, so this spelling mistake usually takes a lot of debugging time. Another way to avoid this error is to register broadcastreceiver through context. registerreceiver (broadcastreceiver, intentfilter) in the Code, so that you can directly write constants instead of specific strings. However, this can only be used to receive broadcast requests. For components that want to serve as public interfaces, they still need to be declared in manifest, such as email. It must be able to process intent. action_send_to must be declared in manifest. 2.
Note that in addition to the data field discussed above, you must note that the data field information must be added to some actions. Otherwise, the data field information may not be received. For example:

<manifest ...>    <receiver ...>           <intent-filter>              <action android:name="android.intent.action.MEDIA_MOUNTED"/>              <action android:name="android.intent.action.MEDIA_UNMOUNTED"/>              <action android:name="android.intent.action.MEDIA_SHARED"/>              <action android:name="android.intent.action.MEDIA_REMOVED"/>              <action android:name="android.intent.action.MEDIA_EJECT"/>              <data android:scheme="file" />           </intent-filter>           <intent-filter>              <action android:name="android.intent.action.PACKAGE_ADDED"/>              <action android:name="android.intent.action.PACKAGE_REMOVED"/>              <action android:name="android.intent.action.PACKAGE_DATA_CLEARED"/>              <data android:scheme="package" />           </intent-filter>   </receiver></manifest>

The datascheme needs to be added when registering the listener for the broadcast with the status change of the mobile phone's external memory card. Otherwise, it will not be received. This also took me a few hours to debug and used context in the code. registerreceiver (broadcastreceiver, intentfilter) cannot be registered. Finally, refer to the practices in music and add datascheme to receive intent in onreceive. Similarly, the following package-related broadcast must be added with datascheme. Otherwise, the broadcast cannot be received. Sadly, for public broadcast systems like this
Intent does not explain how to use it in the intent document. If there is no reference case, I believe it takes some time to find out why the intent cannot be received.
In addition to datascheme, there is also a mimetype, which must be added to the public interface of the system. For example, to process intent. action_sentto by email, you need to declare it as follows:

<manifest ...>    <activity android:name="EmailComposer">           <intent-filter>              <action android:name="android.intent.action.SEND"/>              <data android:mimeType="image/*" />           </intent-filter>   </activity></manifest>

3. Pay attention to the category field.
If the correct Category field is not written to intentfilter, intent cannot be received. For example:

<manifest ...>    <receiver ...>            <intent-filter>                <action android:name="com.hilton.controlpanel.action.BUTTON_ACTION" />                <category android:name="com.hilton.controlpanel.category.SELF_MAINTAIN" />            </intent-filter>   </receiver></manifest>

If you remove the category, you cannot receive the intent either. Of course, it depends on how the intent is sent. If the intent is not added with the category when it is sent, you do not have to add the category to the intentfilter.
In short, for intent, ensure that the sending and receiving are completely consistent, otherwise the system will not be able to find the corresponding match, and the program will not be able to receive intent.
For default category, you should also note that if it is an implicit intent for the activity, if there is no other category, you must add default category. Because the system will be in context. startactivity (intent) and context. startactivityforresult (
Add default category to intent. For context. sendbroadcast (intent), context. sendorderedbroadcast (intent), contxt. sendstickybroadcast (intent) and context. bindservice (intent) context. startservice (intent) does not add default category.
In addition, try to combine the actions into an intentfilter. Because an intentfilter object is created for each intentfilter tag, if you write a few, there will be several objects, which will not only consume resources but also consume more time during matching, this is because an intentfilter object and an intentfilter object are required for query matching. Until the best match is found or until all intentfilters are checked.
Intentfilter matching rules

1. The action field is used to match a basic field in intent, which is also relatively simple. It is a string. If it is equal, the match is successful. Otherwise, the target is not found. However, note that if intentfilter does not specify action, it will not match any implicit intent, and it can only be explicitly matched with intent. In turn, if intent does not specify the action, it can match the intentfilter containing any action, but it cannot match the intentfilter without the specified action. For actions, you should pay attention to spelling errors, because the declared actions in the androidmanifest file are strings and will not be checked during compilation. during runtime, if the action is spelled incorrectly, the matching will fail, either the program cannot work normally or an exception is thrown.

2. Use the Category field to match. For activity, if you want to process the implicit intent, and except intent. action_main, you must specify the category as default. Otherwise, the activity will not be matched. Because context. startactivity () and context. startactivityforresult () are automatically added with default category. In other cases, service and broadcastreceiver do not. For service and broadcastreceiver, if category is not specified in intent, it is not required to be specified in its intentfilter.

3. Matching with data fields is relatively complicated. Generally, data contains Uri, scheme (content, file, HTTP), and type (mimetype). There are two methods for intent:

Intent. setdata (URI); // a URI in which scheme contains intent. settype (string); // specify the mimetype, such as 'image/JPEG 'and 'audio/MPEG' intent. setdataandtype (Uri, string); // The simple call method of the preceding two methods.

For intentfilter, you need to set scheme and type. scheme is a URI restriction. The target needs to restrict scheme because scheme can tell the directory where to get the file pointed to by the URI, type is the type restriction of mimetype.

      <intent-filter>           <action android:name="android.intent.action.SEND" />           <category android:name="android.intent.category.DEFAULT" />           <data android:scheme="content" android:mimeType="image/*" />      </intent-filter>

There are four rules for data matching:

A. if the intent does not specify data-related fields, it can only match the intentfilter with no data specified. That is to say, if an intent does not specify any data (Uri and type), it can only match the intentfilter without specifying any data (scheme and type.

B. If an intent only specifies the URI but does not have the type (and the type cannot be analyzed from the URI), it can only match the intentfilter that only specifies the corresponding scheme and does not specify the type. In practice, if an intent is sending an email or making a call, their intent is like this: "mailto: someone@sb.com" and "Tel: 1234567 ". In other words, these Uris are data rather than data addresses. For example, dialer in phone has the following intentfilter:

<intent-filter>    <action android:name="android.intent.action.CALL" />    <category android:name="android.intent.category.DEFAULT" />    <data android:scheme="tel" /></intent-filter>

Another example is the intentfilter for processing SD status changes:

<intent-filter>      <action android:name="android.intent.action.MEDIA_MOUNTED"/>      <action android:name="android.intent.action.MEDIA_UNMOUNTED"/>      <action android:name="android.intent.action.MEDIA_SHARED"/>      <action android:name="android.intent.action.MEDIA_REMOVED"/>      <action android:name="android.intent.action.MEDIA_EJECT"/>      <category android:name="android.intent.category.DEFAULT" />             <data android:scheme="file" /></intent-filter>

Another example is the intentfilter to handle package status changes:

<intent-filter>      <action android:name="android.intent.action.PACKAGE_ADDED"/>      <action android:name="android.intent.action.PACKAGE_REMOVED"/>      <action android:name="android.intent.action.PACKAGE_DATA_CLEARED"/>      <category android:name="android.intent.category.DEFAULT" />      <data android:scheme="package" /><intent-filter>

However, it is recommended that you do not specify only the URI but not the type of the intent to operate on the data. Because this usually matches a lot

C. If a intent only specifies the type but does not specify the URI, it can only match the intentfitler that only specifies the corresponding type and does not specify scheme.

D. if an intent has Uri and type, it will match: 1 ). intentfilter that both Uri and type match; 2 ). first, type must be matched. In addition, if the intent URI is content: or file:, and the intentfilter does not specify the intentfilter of scheme. For Android, content and file are the most common and most commonly used scheme systems. Therefore, they are treated as default values.

In addition, you must note that because the type is mimetype, wildcards are allowed. For example, 'image/* 'can match all types starting with 'image, that is to say, it can match all the images.

Data Matching example

If there are four activities in the system, the intentfilter of A is like this:

    <activity ...>            <intent-filter>                <action android:name="android.intent.action.SEND" />                <category android:name="android.intent.category.DEFAULT" />                <data android:scheme="content" android:mimeType="image/*" />            </intent-filter>   </activity>

This indicates that a can send all image types, and the content must be provided by contentprovider, that is, the URI must start with "content: //"
Another activity B declares it like this:

    <activity ...>            <intent-filter>                <action android:name="android.intent.action.SEND" />                <category android:name="android.intent.category.DEFAULT" />                <data android:scheme="file" android:mimeType="image/*" />            </intent-filter>   </activity>

This indicates that B can send all images, but the content must be a separate file, that is, the URI must start with "file: //"
Another C statement is as follows:

    <activity ...>            <intent-filter>                <action android:name="android.intent.action.SEND" />                <category android:name="android.intent.category.DEFAULT" />            </intent-filter>   </activity>

This indicates that C can only receive actions that do not specify any Uri and type as send intent.
And D declares it like this:

    <activity ...>            <intent-filter>                <action android:name="android.intent.action.SEND" />                <category android:name="android.intent.category.DEFAULT" />                <data android:mimeType="image/*" />            </intent-filter>   </activity>

This indicates that D can send all images, whether in the database (content) or a separate file (file ).
If an intent is written as follows:

Intent share = new Intent(Intent.ACTION_SEND);startActivity(share);

Therefore, it can only match C, because C does not specify the data and type, and action is send. According to rule a, it can only match activity. However, if you add additional conditions to intent

share.setDataAndType(uri,"image/jpeg");

If the URI is the database content, it will match a. If it is a file, it will match B. However, both content and file match D because it can process images stored in any form. But it never matches C, because C does not declare the data field, so it does not match.
Therefore, we usually want to write components as common system interfaces like this:

    <activity ...>            <intent-filter>                <!-- implement public actions such as View, Edit, Pick or Send -->                <action android:name="android.intent.action.SEND" />                <!-- never forget default category, otherwise your activity never receives intents -->                <category android:name="android.intent.category.DEFAULT" />                <!-- specify mimeType to constrain data type, receive data from both content provider and file -->                <data android:mimeType="image/*" />                <!-- specify scheme to constrain data source, if necessary -->                <data android:shceme="http" />            </intent-filter>   </activity>

Intent and intentfilter have a lot of precautions for the component activity, but there are not so many precautions for service and broadcastreceiver, because category and data are usually not required for service and broadcastreceiver. But there are also exceptions, such as the SD-related broadcast and application installation-related broadcast mentioned above.
Note that if you use context. startactivity () or context. startactivityforresult (), context. bindservice () and context. startservice (). if the system does not match the target activity and service for intent, runtimeexception (activitynotfoundexception) will be thrown. If multiple targets match at the same time, the user will select which one to use in the form of a list.
Use intentfilter matching to query available components

Intent and intentfilter can be used not only for Component Reuse, but also for querying the system where components can do what. For example, the launcher will list many applications. In fact, this statement is not accurate. It should be that all the components that can start an application are listed above (for example, dialer and contacts belong to the same application contacts, but there are two in launcher, one is Dialer and the other is contacts. How is launcher implemented? It is impossible to check system files to see which application files exist and then list them. By querying the intent, it queries all android. Intent. Action. Main and Android. Intent. category.
The launcher activity information is retrieved, and their names and icons are listed. Similarly, we can obtain components with specific features in this way. For details, refer to an article in the SDK (resources-> articles-> can I use this intent ?), It is detailed and has sample code.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.