2020-04-08-Android Intent的显式调用和隐

2020-04-11  本文已影响0人  耿望

ComponentName

如果在intent中指定了组件名,一般称为显式调用。

            Intent intent = new Intent(FullscreenActivity.this, SecondActivity.class);
            startActivity(intent);

这段代码实际上是在Intent中创建了一个ComponentName。

    public Intent(Context packageContext, Class<?> cls) {
        mComponent = new ComponentName(packageContext, cls);
    }

IntentFilter

我们使用隐式调用的时候需要注意,如果不指定Category,系统会默认给Intent加上一个DEFAULT类型的Category,所以最好在Manifest中声明这个Category。

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

1.action

            Intent intent = new Intent(Intent.ACTION_CALL);
            startActivity(intent);

2.category
category跟action不同,action只要有一个匹配即可,但是category要求每一个都匹配。

        <activity android:name=".SecondActivity">
            <intent-filter>
                <action android:name="android.intent.action.CALL"/>
                <category android:name="com.one.new.world.category"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </activity>
            Intent intent = new Intent();
            intent.addCategory("com.one.new.world.category");
            intent.addCategory(Intent.CATEGORY_DEFAULT);
            intent.setPackage(getPackageName());
            startActivity(intent);

3.data

        <activity android:name=".SecondActivity">
            <intent-filter>
                <action android:name="android.intent.action.CALL"/>
                <category android:name="com.one.new.world.category"/>
                <category android:name="android.intent.category.DEFAULT"/>
                <data android:mimeType="image/jpeg" />
            </intent-filter>
        </activity>
            Intent intent = new Intent();
            intent.setDataAndType(Uri.EMPTY, "image/jpeg");
            intent.setPackage(getPackageName());
            startActivity(intent);

IntentFilter.match

从源码可以看到Intent的匹配过程。

  1. 首先匹配action;只要匹配到其中一个action即可,不匹配直接返回;
  2. 然后通过matchData方法匹配data;
  3. 最后通过matchCategories方法匹配categories;
    public final int match(String action, String type, String scheme,
            Uri data, Set<String> categories, String logTag) {
        if (action != null && !matchAction(action)) {//1
            if (false) Log.v(
                logTag, "No matching action " + action + " for " + this);
            return NO_MATCH_ACTION;
        }

        int dataMatch = matchData(type, scheme, data);//2
        if (dataMatch < 0) {
            if (false) {
                if (dataMatch == NO_MATCH_TYPE) {
                    Log.v(logTag, "No matching type " + type
                          + " for " + this);
                }
                if (dataMatch == NO_MATCH_DATA) {
                    Log.v(logTag, "No matching scheme/path " + data
                          + " for " + this);
                }
            }
            return dataMatch;
        }

        String categoryMismatch = matchCategories(categories);//3
        if (categoryMismatch != null) {
            if (false) {
                Log.v(logTag, "No matching category " + categoryMismatch + " for " + this);
            }
            return NO_MATCH_CATEGORY;
        }

        // It would be nice to treat container activities as more
        // important than ones that can be embedded, but this is not the way...
        if (false) {
            if (categories != null) {
                dataMatch -= mCategories.size() - categories.size();
            }
        }

        return dataMatch;
    }

接下来看看matchData方法:

    public final int matchData(String type, String scheme, Uri data) {
        final ArrayList<String> types = mDataTypes;
        final ArrayList<String> schemes = mDataSchemes;

        int match = MATCH_CATEGORY_EMPTY;

        if (types == null && schemes == null) {
            return ((type == null && data == null)
                ? (MATCH_CATEGORY_EMPTY+MATCH_ADJUSTMENT_NORMAL) : NO_MATCH_DATA);
        }

        if (schemes != null) {
            if (schemes.contains(scheme != null ? scheme : "")) {
                match = MATCH_CATEGORY_SCHEME;
            } else {
                return NO_MATCH_DATA;
            }

            final ArrayList<PatternMatcher> schemeSpecificParts = mDataSchemeSpecificParts;
            if (schemeSpecificParts != null && data != null) {
                match = hasDataSchemeSpecificPart(data.getSchemeSpecificPart())
                        ? MATCH_CATEGORY_SCHEME_SPECIFIC_PART : NO_MATCH_DATA;
            }
            if (match != MATCH_CATEGORY_SCHEME_SPECIFIC_PART) {
                // If there isn't any matching ssp, we need to match an authority.
                final ArrayList<AuthorityEntry> authorities = mDataAuthorities;
                if (authorities != null) {
                    int authMatch = matchDataAuthority(data);
                    if (authMatch >= 0) {
                        final ArrayList<PatternMatcher> paths = mDataPaths;
                        if (paths == null) {
                            match = authMatch;
                        } else if (hasDataPath(data.getPath())) {
                            match = MATCH_CATEGORY_PATH;
                        } else {
                            return NO_MATCH_DATA;
                        }
                    } else {
                        return NO_MATCH_DATA;
                    }
                }
            }
            // If neither an ssp nor an authority matched, we're done.
            if (match == NO_MATCH_DATA) {
                return NO_MATCH_DATA;
            }
        } else {
            // Special case: match either an Intent with no data URI,
            // or with a scheme: URI.  This is to give a convenience for
            // the common case where you want to deal with data in a
            // content provider, which is done by type, and we don't want
            // to force everyone to say they handle content: or file: URIs.
            if (scheme != null && !"".equals(scheme)
                    && !"content".equals(scheme)
                    && !"file".equals(scheme)) {
                return NO_MATCH_DATA;
            }
        }

        if (types != null) {
            if (findMimeType(type)) {
                match = MATCH_CATEGORY_TYPE;
            } else {
                return NO_MATCH_TYPE;
            }
        } else {
            // If no MIME types are specified, then we will only match against
            // an Intent that does not have a MIME type.
            if (type != null) {
                return NO_MATCH_TYPE;
            }
        }

        return match + MATCH_ADJUSTMENT_NORMAL;
    }

最后看下matchCategories,必须要所有category匹配才能成功匹配。

    public final String matchCategories(Set<String> categories) {
        if (categories == null) {
            return null;
        }

        Iterator<String> it = categories.iterator();

        if (mCategories == null) {
            return it.hasNext() ? it.next() : null;
        }

        while (it.hasNext()) {
            final String category = it.next();
            if (!mCategories.contains(category)) {
                return category;//1
            }
        }

        return null;
    }
上一篇下一篇

猜你喜欢

热点阅读