深入分析Intent匹配查詢 - 新聞資訊 - 雲南小程序開發|雲南軟件開發|雲南網站建設-昆明融晨信息技術有限公司

159-8711-8523

雲南網建設/小程序開發/軟件開發

知識

不(bù)管是(shì)網站,軟件還是(shì)小程序,都要(yào / yāo)直接或間接能爲(wéi / wèi)您産生價值,我們在(zài)追求其視覺表現的(de)同時(shí),更側重于(yú)功能的(de)便捷,營銷的(de)便利,運營的(de)高效,讓網站成爲(wéi / wèi)營銷工具,讓軟件能切實提升企業内部管理水平和(hé / huò)效率。優秀的(de)程序爲(wéi / wèi)後期升級提供便捷的(de)支持!

您當前位置>首頁 » 新聞資訊 » 技術分享 >

深入分析Intent匹配查詢

發表時(shí)間:2020-11-5

發布人(rén):融晨科技

浏覽次數:45


尊崇本創兇http://blog.csdn.net/yuanzeyao/article/details/42243583



正在(zài)前裏的(de)一沃那粕拘,我麽宏細闡發了(le/liǎo)PackageManagerService的(de)娼過程(正在(zài)背狼9依φ谥那粕拘,爲(wéi / wèi)了(le/liǎo)便當,我會粗PackageManagerService簡稱PMS),PMS正在(zài)平的(de)過程中,會來(lái)膳體系app跟映收拆置的(de)app,而(ér)後粗那些app的(de)疑密保存迪蘋皓肥據機閉中,正在(zài)那篇沃那粕拘,我們會接族诎辣郴沃那啓持絕闡發Intent婚配抽芽過程,如出(chū)有雅對PMS出(chū)有是(shì)很生悉的(de)同窗倡議先來(lái)掃瞄前辣郴沃那啓PackageManagerService平過程闡發。


做爲(wéi / wèi)一名Android App斥地(dì / de)着棘喂好你對Intent的(de)利用實臨生悉出(chū)庸凝了(le/liǎo),比方我念正在(zài)一個(gè)Activity中平别的(de)一個(gè)Activity,會利用來(lái)郝代亂孀

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

以(yǐ)梢法稱慰吸示Intent調用,誠然逢供時(shí)辰我們會利用隐式Intent,比方兇

Intent intent=new Intent("com.android.demo");
this.startActivity(intent);

果爲(wéi / wèi)Intent的(de)利用同常複純,所以(yǐ)正在(zài)那裏我出(chū)有念再來(lái)花太多光丫淮描繪它了(le/liǎo),我們那老是(shì)要(yào / yāo)哪當ツ倒源碌濫角度來(lái)懂裏經過過程Intent是(shì)如何婚配Acitivity的(de)(Service,Receiver講理也(yě)是(shì)好出(chū)有逗媚)。
我們曲接哪當ツ倒startActivity函肥初步伴(提示兇我利用的(de)是(shì)4.1源碼,出(chū)有卑版本的(de)源碼話苄些收收),正在(zài)那裏,先給出(chū)一張時(shí)序圖,而(ér)後跟着時(shí)序圖源碼。
[img]http://img.blog.csdn.net/20141229214350896?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveXVhbnpleWFv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center

圖1-1
目據圖1-1,當我們調用Activity的(de)startActivity辦房啾,實正在(zài)調用的(de)便是(shì)調用ContextImpl的(de)startActivity辦法

    public void startActivity(Intent intent, Bundle options) {
        if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
            throw new AndroidRuntimeException(
                    "Calling startActivity() from outside of an Activity "
                    + " context requires the FLAG_ACTIVITY_NEW_TASK flag."
                    + " Is this really what you want?");
        }
        mMainThread.getInstrumentation().execStartActivity(
            getOuterContext(), mMainThread.getApplicationThread(), null,
            (Activity)null, intent, -1, options);
    }

正在(zài)ContextImple的(de)startActivity辦法中,會調用Instrumentation的(de)execStartActivity辦犯,那個(gè)辦法我便出(chū)有揭出(chū)源碼了(le/liǎo),它琅春沐正在(zài)便是(shì)調用了(le/liǎo)ActivityManagerService的(de)startActivity辦犯,那個(gè)辦法琅春沐正在(zài)便是(shì)調用了(le/liǎo)ActivityStack的(de)startActivityMayWait辦犯,弄辦法逢調用了(le/liǎo)本身的(de)resolveActivity辦犯,末了(le/liǎo)調用了(le/liǎo)PMS的(de)resolveIntent辦法了(le/liǎo),到(dào)那裏末于(yú)睹到(dào)了(le/liǎo)PMS了(le/liǎo),正在(zài)resolveIntent辦法琅春沔便是(shì)調用了(le/liǎo)本身的(de)queryIntentActivities辦犯,queryIntentActivities會前來(lái)一個(gè)ActivityInfo東西,我們知講一個(gè)ActivityInfo東西便是(shì)一個(gè)Activity的(de)檔氨長具,記麓嗨一個(gè)Acitivity的(de)全部的(de)疑密〖怯裏給出(chū)queryIntentActivities的(de)源碼

public List<ResolveInfo> queryIntentActivities(Intent intent,
            String resolvedType, int flags, int userId) {
        if (!sUserManager.exists(userId)) return null;
        ComponentName comp = intent.getComponent();
        if (comp == null) {
            if (intent.getSelector() != null) {
                intent = intent.getSelector(); 
                comp = intent.getComponent();
            }
        }
        if (comp != null) {
            final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
            final ActivityInfo ai = getActivityInfo(comp, flags, userId);
            if (ai != null) {
                final ResolveInfo ri = new ResolveInfo();
                ri.activityInfo = ai;
                list.add(ri);
            }
            return list;
        }
        synchronized (mPackages) {
            final String pkgName = intent.getPackage();
            if (pkgName == null) {
                return mActivities.queryIntent(intent, resolvedType, flags, userId);
            }
            final PackageParser.Package pkg = mPackages.get(pkgName);
            if (pkg != null) {
				// C
                return mActivities.queryIntentForPackage(intent, resolvedType, flags,
                        pkg.activities, userId);
            }
            return new ArrayList<ResolveInfo>();
        }
    }
對膳春沔的(de)代碼,可能看出(chū):
如出(chū)有雅Intent 指渾跋扈了(le/liǎo)然Componet,那孟副接經過過程Componet便可能找到(dào)ActivityInfo
如出(chū)有遜矢定了(le/liǎo)packagename,那麽可以(yǐ)經過過程packagename找到(dào)Package,而(ér)後經過過程Package包露的(de)Activities中盡鋅配
如出(chū)有雅緊出(chū)有滿足,那夢孰要(yào / yāo)齊體系盡鋅配。


寫到(dào)那裏,我黴┬須要(yào / yāo)對殺郴沃那粕拘的(de)一皓緊張肥據機閉盡鋅念。
回念1兇PackageManagerService中有兩個(gè)scanPackageLI,第一個(gè)scanPackageLI的(de)第一個(gè)好肥是(shì)File,它的(de)任務便是(shì)粗指定的(de)文取(apk)的(de)AndroidManifest.xml文取分解成PackageParser.Package東西。我們看看那個(gè)東西有藏些字段伴
[img]http://img.blog.csdn.net/20141229221514312?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveXVhbnpleWFv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center

圖1-2


那裏我僅僅列出(chū)了(le/liǎo)比較重依閱字段,疑好哪當ツ倒家看了(le/liǎo)背龊喜鹱,Package琅春沔存儲了(le/liǎo)一個(gè)apk中的(de)全部疑密,此末露全部的(de)Activity,全部的(de)Service等底箧膦且正在(zài)PMS中有一個(gè)HashMap保存了(le/liǎo)全部的(de)Pacakge,此中key便是(shì)包名


回念2N第兩個(gè)scanPackageLI中,會粗指定Package中的(de)一皓疑密盡洩墨湧,比方會粗activities中的(de)全部Activity好加ActivityIntentResolver範例的(de)鄙mActivities鄙中〈圄意那裏道(dào)的(de)Activity跟我們平常平但凡用的(de)Activity出(chū)有是(shì)一個(gè)範例,它的(de)持絕機閉來(lái)郝兇
[img]http://img.blog.csdn.net/20141229224156659?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveXVhbnpleWFv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center

圖1-3


回念3NscanPackageLI中,經過過程調用ActivityIntentResolver的(de)addActivity辦犯,粗指定的(de)PackageParser.Activity保磁揀來(lái),我們看看addActivity做兩如何。

/**
     * @param a
     * 		要(yào / yāo)被保存的(de)Activity
     * @param type
     * 		"activity" or "recevier"
     */
    public final void addActivity(PackageParser.Activity a, String type) {
        final boolean systemApp = isSystemApp(a.info.applicationInfo);
        //保存迪蘋個(gè)HashMap中
        mActivities.put(a.getComponentName(), a);
        final int NI = a.intents.size();
        //遍曆Activity中全部的(de)IntentFilter,而(ér)後調用addFilter辦法盡行保存
        for (int j=0; j<NI; j++) {
            PackageParser.ActivityIntentInfo intent = a.intents.get(j);
            if (!systemApp && intent.getPriority() > 0 && "activity".equals(type)) {
                intent.setPriority(0);
                Log.w(TAG, "Package " + a.info.applicationInfo.packageName + " has activity "
                        + a.className + " with priority > 0, forcing to 0");
            }
            if (DEBUG_SHOW_INFO) {
                Log.v(TAG, "    IntentFilter:");
                intent.dump(new LogPrinter(Log.VERBOSE, TAG), "      ");
            }
            if (!intent.debugCheck()) {
                Log.w(TAG, "==> For Activity " + a.info.name);
            }
            addFilter(intent);
        }
    }

邏輯比較複純,曲接盡進addFilter函肥,看看做烈姗甚麽

public void addFilter(F f) {
        mFilters.add(f);
        int numS = register_intent_filter(f, f.schemesIterator(),
                mSchemeToFilter, "      Scheme: ");
        int numT = register_mime_types(f, "      Type: ");
        if (numS == 0 && numT == 0) {
            register_intent_filter(f, f.actionsIterator(),
                    mActionToFilter, "      Action: ");
        }
        if (numT != 0) {
            register_intent_filter(f, f.actionsIterator(),
                    mTypedActionToFilter, "      TypedAction: ");
        }
    }

此中mFilters是(shì)一個(gè)HashSet範例鄙,那個(gè)辦法尾俠粗ActivityIntentInfo範例鄙保存到(dào)mFilters中,接着調用了(le/liǎo)register_intent_filter辦法

private final int register_intent_filter(F filter, Iterator<String> i,
            HashMap<String, ArrayList<F>> dest, String prefix) {
        if (i == null) {
            return 0;
        }

        int num = 0;
        while (i.hasNext()) {
            String name = i.next();
            num++;
            if (localLOGV) Slog.v(TAG, prefix + name);
            ArrayList<F> array = dest.get(name);
            if (array == null) {
                //Slog.v(TAG, "Creating new array for " + name);
                array = new ArrayList<F>();
                dest.put(name, array);
            }
            array.add(filter);
        }
        return num;
    }

正在(zài)看代碼之(zhī)峭宮必要(yào / yāo)生悉那裏的(de)肥據機閉,filter便蝦帽于(yú)一個(gè)IntentFilter,i 是(shì)一個(gè)叠代器,經過過程它我們可能遍曆filter全部的(de)scheme,dest便是(shì)一個(gè)HashMap,key是(shì)filter的(de)scheme,值便是(shì)一個(gè)ArrayList<F>,實正在(zài)便是(shì)經過過程遍曆一個(gè)IntentFilter的(de)全部scheme,目據那個(gè)scheme找到(dào)洞喀的(de)ArrayList<F>,而(ér)後粗那個(gè)Filter放進ArrayList<F>,而(ér)後前來(lái)scheme的(de)個(gè)肥。


如古回到(dào)addFilter辦犯,接着會帶調用register_mime_types辦犯,一樣,看看那個(gè)辦法做兩如何

  private final int register_mime_types(F filter, String prefix) {
        final Iterator<String> i = filter.typesIterator();
        if (i == null) {
            return 0;
        }

        int num = 0;
        while (i.hasNext()) {
            String name = i.next();
            num++;
            if (localLOGV) Slog.v(TAG, prefix + name);
            String baseName = name;
            final int slashpos = name.indexOf('/');
            if (slashpos > 0) {
                baseName = name.substring(0, slashpos).intern();
            } else {
                name = name + "/*";
            }

            ArrayList<F> array = mTypeToFilter.get(name);
            if (array == null) {
                //Slog.v(TAG, "Creating new array for " + name);
                array = new ArrayList<F>();
                mTypeToFilter.put(name, array);
            }
            array.add(filter);

            if (slashpos > 0) {
                array = mBaseTypeToFilter.get(baseName);
                if (array == null) {
                    //Slog.v(TAG, "Creating new array for " + name);
                    array = new ArrayList<F>();
                    mBaseTypeToFilter.put(baseName, array);
                }
                array.add(filter);
            } else {
                array = mWildTypeToFilter.get(baseName);
                if (array == null) {
                    //Slog.v(TAG, "Creating new array for " + name);
                    array = new ArrayList<F>();
                    mWildTypeToFilter.put(baseName, array);
                }
                array.add(filter);
            }
        }

        return num;
    }

那個(gè)辦法的(de)成不(bù)俗跟register_intent_filter辦繁腸能是(shì)一樣的(de),隻出(chū)庸凝register_intent_filter是(shì)處理scheme的(de),那老是(shì)處理type的(de),type的(de)邏輯比scheme複純。scheme隻用了(le/liǎo)一個(gè)mSchemeToFilter存儲,而(ér)type用了(le/liǎo)三個(gè),他(tā)們辨别是(shì)兇
mWildTypeToFilter兇用于(yú)保存扇髅了(le/liǎo)Data範例“image/*”的(de)IntentFilter,但是(shì)扇髅“image/jpeg”的(de)出(chū)有算正在(zài)你

mTypeToFilter脅瘘露了(le/liǎo)mWildTypeToFilter和(hé / huò)指渾跋扈了(le/liǎo)然Data範例爲(wéi / wèi)肯侗趁肥的(de)IntentFilter疑密,如“image/jpeg”跟“image/*”範例

mBaseTypeToFilter兇保存MIME中Base範例的(de)IntentFilter,但是(shì)出(chū)誘露Sub type爲(wéi / wèi)"*"的(de)IntentFilter




實正在(zài)膳春沔回系濫3裏緊恃舭辣郴沃那啓擋刳容,下裏便初步研究一下queryIntentActivities的(de)邏輯凹

public List<ResolveInfo> queryIntentActivities(Intent intent,
            String resolvedType, int flags, int userId) {
        if (!sUserManager.exists(userId)) return null;
        ComponentName comp = intent.getComponent();
        if (comp == null) {
            if (intent.getSelector() != null) {
                intent = intent.getSelector(); 
                comp = intent.getComponent();
            }
        }

        if (comp != null) {
            final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
            final ActivityInfo ai = getActivityInfo(comp, flags, userId);
            if (ai != null) {
                final ResolveInfo ri = new ResolveInfo();
                ri.activityInfo = ai;
                list.add(ri);
            }
            return list;
        }

        // reader
        synchronized (mPackages) {
            final String pkgName = intent.getPackage();
            if (pkgName == null) {
                return mActivities.queryIntent(intent, resolvedType, flags, userId);
            }
            final PackageParser.Package pkg = mPackages.get(pkgName);
            if (pkg != null) {
                return mActivities.queryIntentForPackage(intent, resolvedType, flags,
                        pkg.activities, userId);
            }
            return new ArrayList<ResolveInfo>();
        }
    }

那朝分代碼邏輯實正在(zài)也(yě)出(chū)有算複純,經過過程Intent你到(dào)ComponetName,如出(chū)有雅ComponetName出(chū)無爲(wéi / wèi)null(表明利用的(de)蝕涸尾悴用),那麽經過過程調用getActivityInfo辦法你到(dào)ActivityInfo。getActivityInfo實正在(zài)便是(shì)到(dào)mActivities琅春沔目據ComponetName你到(dào)PackageParser.Activity東西,并經過過程調用PackageParser.generateActivityInfo辦法粗PackageParser.Activity東西變成ActivityInfo東西。如出(chū)有雅ComponetName爲(wéi / wèi)null(隐尾悴用),那麽便要(yào / yāo)分爲(wéi / wèi)兩種環境兇
第腋V環境兇經過過程intent你到(dào)包名爲(wéi / wèi)Null,那麽調用ActivityIntentResolver的(de)queryIntent辦法

      public List<ResolveInfo> queryIntent(Intent intent, String resolvedType,
                boolean defaultOnly, int userId) {
            if (!sUserManager.exists(userId)) return null;
            mFlags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0;
            return super.queryIntent(intent, resolvedType, defaultOnly, userId);
        }

代碼很少,調用了(le/liǎo)IntentResolver的(de)queryIntent,曲接看queryIntent的(de)源碼伴

public List<R> queryIntent(Intent intent, String resolvedType, boolean defaultOnly,
            int userId) {
        String scheme = intent.getScheme();

        ArrayList<R> finalList = new ArrayList<R>();

        final boolean debug = localLOGV ||
                ((intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0);

        if (debug) Slog.v(
            TAG, "Resolving type " + resolvedType + " scheme " + scheme
            + " of intent " + intent);

        ArrayList<F> firstTypeCut = null;
        ArrayList<F> secondTypeCut = null;
        ArrayList<F> thirdTypeCut = null;
        ArrayList<F> schemeCut = null;

        // If the intent includes a MIME type, then we want to collect all of
        // the filters that match that MIME type.
        if (resolvedType != null) {
            int slashpos = resolvedType.indexOf('/');
            if (slashpos > 0) {
                final String baseType = resolvedType.substring(0, slashpos);
                if (!baseType.equals("*")) {
                    if (resolvedType.length() != slashpos+2
                            || resolvedType.charAt(slashpos+1) != '*') {
                        // Not a wild card, so we can just look for all filters that
                        // completely match or wildcards whose base type matches.
                        firstTypeCut = mTypeToFilter.get(resolvedType);
                        if (debug) Slog.v(TAG, "First type cut: " + firstTypeCut);
                        secondTypeCut = mWildTypeToFilter.get(baseType);
                        if (debug) Slog.v(TAG, "Second type cut: " + secondTypeCut);
                    } else {
                        // We can match anything with our base type.
                        firstTypeCut = mBaseTypeToFilter.get(baseType);
                        if (debug) Slog.v(TAG, "First type cut: " + firstTypeCut);
                        secondTypeCut = mWildTypeToFilter.get(baseType);
                        if (debug) Slog.v(TAG, "Second type cut: " + secondTypeCut);
                    }
                    // Any */* types always apply, but we only need to do this
                    // if the intent type was not already */*.
                    thirdTypeCut = mWildTypeToFilter.get("*");
                    if (debug) Slog.v(TAG, "Third type cut: " + thirdTypeCut);
                } else if (intent.getAction() != null) {
                    // The intent specified any type ({@literal *}/*).  This
                    // can be a whole heck of a lot of things, so as a first
                    // cut let's use the action instead.
                    firstTypeCut = mTypedActionToFilter.get(intent.getAction());
                    if (debug) Slog.v(TAG, "Typed Action list: " + firstTypeCut);
                }
            }
        }

        // If the intent includes a data URI, then we want to collect all of
        // the filters that match its scheme (we will further refine matches
        // on the authority and path by directly matching each resulting filter).
        if (scheme != null) {
            schemeCut = mSchemeToFilter.get(scheme);
            if (debug) Slog.v(TAG, "Scheme list: " + schemeCut);
        }

        // If the intent does not specify any data -- either a MIME type or
        // a URI -- then we will only be looking for matches against empty
        // data.
        if (resolvedType == null && scheme == null && intent.getAction() != null) {
            firstTypeCut = mActionToFilter.get(intent.getAction());
            if (debug) Slog.v(TAG, "Action list: " + firstTypeCut);
        }

        FastImmutableArraySet<String> categories = getFastIntentCategories(intent);
        if (firstTypeCut != null) {
            buildResolveList(intent, categories, debug, defaultOnly,
                    resolvedType, scheme, firstTypeCut, finalList, userId);
        }
        if (secondTypeCut != null) {
            buildResolveList(intent, categories, debug, defaultOnly,
                    resolvedType, scheme, secondTypeCut, finalList, userId);
        }
        if (thirdTypeCut != null) {
            buildResolveList(intent, categories, debug, defaultOnly,
                    resolvedType, scheme, thirdTypeCut, finalList, userId);
        }
        if (schemeCut != null) {
            buildResolveList(intent, categories, debug, defaultOnly,
                    resolvedType, scheme, schemeCut, finalList, userId);
        }
        sortResults(finalList);

        if (debug) {
            Slog.v(TAG, "Final result list:");
            for (R r : finalList) {
                Slog.v(TAG, "  " + r);
            }
        }
        return finalList;
    }

那個(gè)函肥看起來(lái)很複純,但是(shì)邏輯很複純,我正在(zài)那裏複純的(de)汨繪一下。
尾銑桤出(chū)有雅給定的(de)Intent包露MIME,便的(de)膳春沔(mTypeToFilter,mWildTypeToFilter,mBaseTypeToFilter)琅訣春譏瘧編符前提的(de)IntentFilter,粗膠匣有雅辨别保存到(dào)firstTypeCut,secondTypeCut,thirdTypeCut中,而(ér)後目據scheme盡鋅配,粗膠匣有雅保存到(dào)schemeCut,末了(le/liǎo)調用buildResolveList辦犯,粗action,scheme,categories等成分随後婚配,粗膠匣有雅保存到(dào)finalList中來(lái),末了(le/liǎo)對finalList盡幸膳序〖欠曛環境闡發完了(le/liǎo)。


第兩種環境兇如出(chū)有雅intent中的(de)包名出(chū)無爲(wéi / wèi)Null,目據包名你到(dào)PackageParser.Package東西,調用ActivityIntentResolver的(de)queryIntentForPackage辦犯4可,此辦法中遍曆PackageParsr.Package中的(de)mactivities東西,粗每個(gè)PackageParser.Activity中的(de)全部IntentFilter好加listCut(一個(gè)ArrayList)中,而(ér)後調用IntentResolve的(de)queryIntentFromList辦犯,正在(zài)queryIntentFromList辦法中,目據給定的(de)Intent的(de)action,categories,scheme,type等疑密婚配listCut中的(de)IntentFilter東西。


好了(le/liǎo)閉于(yú)Intent的(de)妤配過程便寫到(dào)那爛埽






相關案例查看更多