When finding a matching component for an implicit intent, both the action, category, data and type are used, i.e., all of them must match.
This means that an intent with only an action will match a receiver with only an action, while an intent with an action and data will only match a receiver with that action and a <data>
element matching the data URI.
Note that extras are never used for matching, which is why when you put your data as an extra instead of using setData()
, you did match your action-only receiver.
Example:
Intent intent = new Intent();
intent.setAction("com.company.ACTION_CUSTOM");
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.setData(Uri.parse("file://somefile.jpg"));
This will for example match a receiver with the following intent filter:
<receiver android:name="com.company.app2.MyBroadcastReceiver" >
<intent-filter>
<action android:name="com.company.ACTION_CUSTOM" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="file" />
</intent-filter>
</receiver>
...because the action, category and data all match.
If the intent filter were to not have any <data>
element, it would only match intents also not having any data.
It's quite common to skip the data for intents using custom actions, especially if used only internally within an app. However, for intents using standard actions such as android.intent.action.VIEW
, data (or type) is critical to make any sensible matching (imagine the chaos if an android.intent.action.VIEW
intent with an image URI as the data would be matched by all components supporting android.intent.action.VIEW
regardless of the type of data!)