Intent匹配規則以及解析框架深刻分析

關於Intent以及IntentFilter的基本知識,你們能夠參閱以下資料,html

                      SDK中對Intent與IntentFilter的介紹  ---- 英文java

                       其中文翻譯以下:
android

                              Android開發之旅: Intents和Intent Filters(理論部分)

 


    我重點分析一下兩個方面:算法

         第一部分 、Intent以及IntentFilter說明以及匹配規則分析數據結構

         第二部分:Intent的解析過程分析app

 

 


 

 第一部分 、Intent以及IntentFilter說明以及匹配規則分析

 

       想當初我看Intent相關知識時,對Intent、IntentFilter的理解就不好勁,總以爲系統定義了一個Intent,爲什麼還要整理個數據結構和算法

  IntentFilter出來"禍害"廣大程序猿呢?但不解歸不解,在具體使用咱可不能含糊,因而只好依葫蘆畫瓢了,反正絕對還不錯。ide

   

 1、溫故而知新 :Intent與IntentFilter兩問。


        *  它們是什麼 ?函數

 

       *  它們的區別在哪兒 ?源碼分析

 

   事實上,這兩個問題能夠概括爲Intent和Intent的主要功能是什麼 ? 你們能夠先捫心自問下,看看你的掌握程度如何 ?

 

   個人理解以下:

 

       * Intent :   主要功能是根據特定的條件找到匹配的組件,繼而對該組件執 行一些操做。好比執行startActivity()時,系統

              首先要找到特定的Activity組件,而後執行onCreate()方法;startService()也得先找的特定的Service組件,而後執行  

               onCreate()或者onStart()方法 。

 

      * IntentFilter :主要功能是爲某個組件向系統註冊一些特性(固然一個組件能夠註冊多個IntentFilter),以便Intent找到對應

             的組件。

 

 

 2、它們之間的關係是如何呢?

 

      經過前面對Intent以及IntentFilter的分析,咱們很容易在語意上得出它們實際上是個先後關係

 

         * IntentFilter在前:任何一個組件必須先經過IntentFilter註冊。

 

        * Intent 在後       :根據特定信息,找到以前以及註冊過的組件。

 

 

  源碼分析:

 

    Intent類源碼(部分) 路徑位於:\frameworks\base\core\java\android\content\Intent.java


[java] view plaincopyprint?

  1. public class Intent implements Parcelable, Cloneable {  

  2.   

  3.     private String mAction;           //action值  

  4.     private Uri mData;                //uri  

  5.     private String mType;             //MimeType  

  6.     private String mPackage;          //所在包名  

  7.     private ComponentName mComponent; //組件信息  

  8.     private int mFlags;               //Flag標誌位  

  9.     private HashSet<String> mCategories; //Category值  

  10.     private Bundle mExtras;           //附加值信息  

  11.     //...  

  12. }  


   IntentFilter類源碼(部分) 路徑位於:\frameworks\base\core\java\android\content\IntentFilter.java

[java] view plaincopyprint?

  1. public class IntentFilter implements Parcelable {  

  2.     //...  

  3.     //保存了全部action字段的值  

  4.     private final ArrayList<String> mActions;  

  5.     //保存了全部Category的值  

  6.     private ArrayList<String> mCategories = null;  

  7.     //保存了全部Schema(模式)的值  

  8.     private ArrayList<String> mDataSchemes = null;  

  9.     //保存了全部Authority字段的值  

  10.     private ArrayList<AuthorityEntry> mDataAuthorities = null;  

  11.     //保存了全部Path的值  

  12.     private ArrayList<PatternMatcher> mDataPaths = null;  

  13.     //保存了全部MimeType的值  

  14.     private ArrayList<String> mDataTypes = null;  

  15.     //...  

  16. }  


 

       PS :你們能夠參詳下Intent與IntentFilter類中不一樣字段的屬性類型。Intent中屬性類型基本上都是單個類型的,而IntentFilter

屬性都是集合類型的。從這方面思考,更能夠加深咱們的理解。

 

 3、Intent匹配規則

 

      匹配種類有以下三種:      

                 *  動做(Action)檢測

                 *  種類(Category)檢測

                 *  數據(Data & MimeType)檢測

 

      比較好理解的是,進行匹配時Intent攜帶的Action字段值和Category字段值必須包含在IntentFilter中,不然匹配失敗。

 

       SDK中說明的具體規則以下:


            *      一個Intent對象既不包含URI,也不包含數據類型 ; 僅當過濾器也不指定任何URIs和數據類型時,才能經過檢測;

              不然不能經過。

 

            *     一個Intent對象包含URI,但不包含數據類型:僅當過濾器也不指定數據類型,同時它們的URI匹配,才能經過檢測。

            例如,mailto:和tel:都不指定實際數據。

 

            *    一個Intent對象包含數據類型,但不包含URI:僅當過濾也只包含數據類型且與Intent相同,才經過檢測。

 

            *    一個Intent對象既包含URI,也包含數據類型(或數據類型可以從URI推斷出) ; 數據類型部分,只有與過濾器中之一

             匹配纔算經過;URI部分,它的URI要出如今過濾器中,或者它有content:或file: URI,又或者過濾器沒有指定URI。

             換句話說,若是它的過濾器僅列出了數據類型,組件假定支持content:和file: 。

 

         PS :可別說我不會總結出來給你們分享,其實我以爲不少知識都須要本身去嘗試,去努力吸取,只要通過本身的消化,

          學到的知識就是本身的了。

 

      上面的規則比較生硬吧。咱們去源碼中去看看Intent與IntentFilter的具體匹配方法吧。

       該方法是IntentFilter中的match()方法,該方法的內部處理邏輯就是按照上面的規則去判斷的,你們能夠仔細體味下,該方法

  咱們在後面講到Intent解析過程時也會用到。 具體邏輯在代碼中進行了說明。

[java] view plaincopyprint?

  1. public class IntentFilter implements Parcelable {  

  2.     //匹配算法,,按照匹配規則進行  

  3.     //Intent與該IntentFilter進行匹配時調用該方法參數表示Intent的相關屬性值  

  4.     public final int match(String action, String type, String scheme,  

  5.             Uri data, Set<String> categories, String logTag){  

  6.         //首先、匹配Action字段  

  7.         if (action != null && !matchAction(action)) {  

  8.             if (Config.LOGV) Log.v(  

  9.                 logTag, "No matching action " + action + " for " + this);  

  10.             return NO_MATCH_ACTION;  

  11.         }  

  12.         //其次、匹配數據(Uri和MimeType)字段  

  13.         int dataMatch = matchData(type, scheme, data);  

  14.         //...  

  15.         //最後,匹配Category字段值  

  16.         String categoryMatch = matchCategories(categories);  

  17.         //...  

  18.     }  

  19.     //...  

  20. }  



    這部分咱們重點講解的知識點有以下:

 

           一、Intent以及IntentFilter的主要職能

           二、Intent與IntentFilter的關係

           三、匹配規則說明

 

 

第二部分、 Intent的解析過程分析

  

       在繼續看本部分以前,但願您最好對PackageManagerService-----程序包管理服務有必定的認知(沒有也是OK的咯)。

  能夠參考下面這篇問題去看看PackageManagerService的功能和相關流程。


         老羅的博客:<<Android應用程序安裝過程源代碼分析>>

           

 

    1、引入PackageManager

           咱們知道Android源碼老是貼心的(不知道有沒有10086貼心),它對外提供了不少藉口供應用程序調用,例如AudioManger

    (音頻管理)、TelephoneManger(電話管理)、一樣也提供了一個包管理-----PackageManager,經過它咱們能夠、獲取應用

    程序包得信息,例如圖標、Lable標籤等。具體關於PackageManager的使用,能夠參考個人另一篇文章 :

 

                       <<Android中獲取應用程序(包)的信息-----PackageManager的使用(一)>>

 

   2、PackageManagerService  ---- 重量級選手

          前面所說PackageManager不過是個傀儡,全部相關的操做都是由PackageManagerService 完成的。這兒咱們簡單的

      分析下PackageManagerService 的特性:

             ①、開機就啓動,由SystemServer進程啓動 ;

             ②、啓動後它會掃描系統中全部應用程序Apk包下的AndroidManifest.xml文件,而後解析全部的

           AndroidManifest.xml文件,繼而造成一個龐大的信息結構樹,而且保存在PackageManagerService 的相關屬性下。

                 它會掃描這兩個目錄:

                                /system/app  ------------------> 系統應用程序

                                /data/app      ------------------> 第三方應用程序(全部安裝的Apk包都會在該目錄下保存一份拷貝)

          掃描完成後,因而全部的信息結構就構建了。PackageManagerService 的四個重要屬性以下:

[java] view plaincopyprint?

  1. class PackageManagerService extends IPackageManager.Stub {  

  2.     //...  

  3.     //保存了全部Activity節點信息 。         自定義類  

  4.     // All available activities, for your resolving pleasure.  

  5.     final ActivityIntentResolver mActivities =  

  6.             new ActivityIntentResolver();  

  7.     //保存了全部BroadcastReceiver節點信息  。  自定義類  

  8.     // All available receivers, for your resolving pleasure.  

  9.     final ActivityIntentResolver mReceivers =  

  10.             new ActivityIntentResolver();  

  11.     //保存了全部Service節點信息。 。  自定義類  

  12.     // All available services, for your resolving pleasure.  

  13.     final ServiceIntentResolver mServices = new ServiceIntentResolver();  

  14.     //保存了全部ContentProvider節點信息 , 以Hash值保存  

  15.     // Keys are String (provider class name), values are Provider.  

  16.     final HashMap<ComponentName, PackageParser.Provider> mProvidersByComponent =  

  17.             new HashMap<ComponentName, PackageParser.Provider>();  

  18.     //...  

  19. }  


 

 

       值得注意這些屬性類型的不一樣。Activity、BroadcastReceiver、Service都採用了自定義類去保存相關信息,從類名上看,

 類結構應該很類似。而ContentProvider只是簡單的採用了HashMap鍵值對去保存了信息? 莫非有錯 ? 咱們回憶下

 AndroidManifest.xml定義組件信息時,Activity、BroadcastReceiver、Service均可以經過<intent-filter>去隱式匹配的,而

 ContentProvider只須要一個Uri數據便可找到對應的ContentProvider組件信息了。 所以才採用了這兩種結構去保存信息。

 

 

       其實咱們經過getPackageManager()方法得到的PackageManager對象,只是PackageManagerService的客戶端,

  該客戶端類是ApplicationPackageManager,它是ContextIml類的內部類,顯然該類存在於用戶空間中。

 

       源代碼(部分)以下:

 

[java] view plaincopyprint?

  1. @Override  

  2. public PackageManager getPackageManager() {  

  3.    //...  

  4.    // Doesn't matter if we make more than one instance.  

  5.    return (mPackageManager = new ApplicationPackageManager(this, pm));  

  6.    //...  

  7. }  

  8. class ContextImpl extends Context {  

  9.     //...  

  10.     /*package*/  

  11.     static final class ApplicationPackageManager extends PackageManager{  

  12.            //...  

  13.            @Override  

  14.            public ActivityInfo getActivityInfo(ComponentName className, int flags){  

  15.                //...  

  16.            }  

  17.              

  18.     }  

  19.     //...  

  20. }  


      它與PackageManagerService的簡單關係以下:


                     

     

  三 、保存數據採用的數據結構和解析算法

 

     一、保存數據採用的數據結構

 

       毫無疑問,保存全部信息是一項很複雜的工程,在具體講解匹配過程時,咱們先看看系統爲了保存這些結構定義的一些

   數據結構。

           

       IntentInfo類:繼承至IntentFilter

               做用:保存了每一個<intent-filter>節點信息

     ActivityIntentInfo類:繼承至IntentInfo

               做用:保存了<activity />節點下的< intent-filter>節點信息

      ServiceIntentInfo:繼承至IntentInfo

             做用:保存了<service />節點下的< intent-filter >節點信息

     Activity類:保存了<activity />節點信息

     Service類:保存了<service />節點信息


 

    PS:這些都是PackageParser類的內部類 。PackageParser的主要功能就是解析AndroidManifest.xml文件

 

      IntentResolver類:模板類,父類,保存了<activity/><service/><receiver />節點的共同信息。

      ActivityIntentResolver類:繼承至IntentResolver類。

            做用:保存了全部<activity/>或者<receiver/>節點信息。(Activity或者BroadcastReceiver信息就是用該自定義類保存的)

     ServiceIntentResolver類:繼承至IntentResolver類,保存了

            做用:保存了全部<service/>節點信息。(Service信息就是用該自定義類保存的)。

 

  一個簡單的UML圖表示以下:  

                                                  

 

   

     二、Intent解析採用的算法

        不一樣的數據結構決定了不一樣的算法,而不一樣的算法又決定着性能,例如時間複雜度以及空間複雜度等。 在具體講解解析

  採用的算法時,咱們先理解下這個情景。

        假設一個女人決定參加一個相親節目(你們能夠理解成《非誠勿擾》),而後她向主辦方提出以下條件:       

                1、身高 ?     175cm以上 ;

                        二、 財富 ?     100萬 ;

                        三、 學歷 ?     本科以上 ;

                           ……

 

     主辦發經理一看,你丫的要求還真高。但客戶是萬能的,該經理也只能去找到知足這些條件的男人咯。

 

       最開始,該經理是這麼想的,我把全部男的都給遍歷一遍,確定把知足這些條件的男人給揪出來。他找啊找,以爲這麼找下去

  是否是太二B了(呵呵,你也是這麼想的嗎?)。經理就開始想:「我爲何不能根據這些條件把全部男的給分紅三個種羣呢?有錢

  的男人在一塊兒,高個子的男人在一塊兒,高學歷的男人在一塊兒,這樣查找起來不是更快嗎 ? 「


      因而,有了以下的劃分:     PS, 你是屬於哪一類額 ? 


                      二B算法(沒有分類)                                                                                    高級點的算法(分類後)

                   


 

       可能你們對這種根據關鍵值分類的好處不能一目瞭然。咱們舉個通常例子吧:

           假設當前共有100個男的。 其中有錢的有20人,高個子有30人,高學歷男人有10人。


       根據第一種算法分類,咱們須要比較100次,而第二種算法咱們總共只須要比較60次。從整個基數來分析,算法確定優化了

       最後,對不一樣的分類中查詢的結果進行組合從新排列下,便可獲得咱們的知足該女性的要求。

          

        一樣的,在進行Intent匹配時,Android也採用了第二種方法來進行算法匹配。它根據一些關鍵值Action、MimeType、

   Schema字段去進行分類。分類以後的集合大體以下:


                               


       因而在進行具體匹配時,咱們只是須要根據關鍵值從不一樣集合中獲取便可。


       事實上,因爲MimeType的通配符(*)的特性,它的匹配能夠說是最難的。參考IntentResolver類,真正的關鍵值以下:

[java] view plaincopyprint?

  1. //模板類 F類型可能爲ActivityIntentInfo或ServiceIntentInfo,R對象是ResolverInfo類  

  2. public class IntentResolver<F extends IntentFilter, R extends Object> {  

  3.     //保存了全部<intent-filter>節點信息  

  4.     //All filters that have been registered.   

  5.     private final HashSet<F> mFilters = new HashSet<F>();  

  6.     /** All of the MIME types that have been registered, such as "image/jpeg", 

  7.      * "image/*", or "{@literal *}/*". 

  8.      */  

  9.     //關鍵值表示MimeType形如:  image/jpeg 、 image/*、/*  類型  

  10.     private final HashMap<String, ArrayList<F>> mTypeToFilter   

  11.       

  12.     /**  

  13.      * The base names of all of all fully qualified MIME types that have been  

  14.      * registered, such as "image" or "*".  Wild card MIME types such as  

  15.      * "image/*" will not be here.  

  16.      */  

  17.     //關鍵值表示MimeType形如:image、 image/*、*  類型  

  18.     private final HashMap<String, ArrayList<F>> mBaseTypeToFilter  

  19.       

  20.     /**  

  21.      * The base names of all of the MIME types with a sub-type wildcard that  

  22.      * have been registered.  For example, a filter with "image/*" will be  

  23.      * included here as "image" but one with "image/jpeg" will not be  

  24.      * included here.  This also includes the "*" for the "{@literal *}/*"  

  25.      * MIME type.  

  26.      */  

  27.     //這個關鍵字段表示MimeType形如 :image、* 類型  

  28.     private final HashMap<String, ArrayList<F>> mWildTypeToFilter   

  29.       

  30.     //All of the URI schemes (such as http) that have been registered.  

  31.     //關鍵值字段表示Schema  

  32.     private final HashMap<String, ArrayList<F>> mSchemeToFilter   

  33.     /** 

  34.      * All of the actions that have been registered, but only those that did 

  35.      * not specify data. 

  36.      */  

  37.     //關鍵值字段表示:Action  

  38.     private final HashMap<String, ArrayList<F>> mActionToFilter  

  39.     //All of the actions that have been registered and specified a MIME type.  

  40.     //關鍵值字段表示:Action和MimeType。 即該<intent-filter>節點必須包含action和MimeType  

  41.     private final HashMap<String, ArrayList<F>> mTypedActionToFilter  

  42. }  


 

      因而,經過這些關鍵字段咱們能夠去特定集合去查找,最後將結果在從新組合下,那不就萬事大吉了。


      最後,咱們經過代碼走讀的方式,以一個查詢Activity的信息的方法,帶領你們去熟悉具體流程。該方法原型爲:

          //經過給定的intent,查詢全部匹配的Activity組件信息

               abstract List<ResolveInfo>   queryIntentActivities(Intent intent, int flags) 

 

 

        PS:其實查詢Activity、Service、BroadcastReceiver的流程基本上是相同的。

 

 

       Step 一、獲取PackageManager代理對象,調用該方法:

[java] view plaincopyprint?

  1. PackageManager mPackageManger = this.getPackageManager() ;  

  2.           

  3.         //爲了說明,這兒咱們簡單查詢一個Intent對象,即全部應用程序的啓動Activity  

  4.         Intent mainIntent = new Intent() ;  

  5.         mainIntent.setAction(Intent.ACTION_MAIN);  

  6.         mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);  

  7.         mPackageManger.queryIntentActivities(mainIntent, 0);  

  8.           

  9.           

  10.        //獲取PackageManager對象  

  11.        @Override  

  12.        public PackageManager getPackageManager() {  

  13.            //...  

  14.            IPackageManager pm = ActivityThread.getPackageManager();  

  15.            if (pm != null) {  

  16.                // Doesn't matter if we make more than one instance.  

  17.                return (mPackageManager = new ApplicationPackageManager(this, pm));  

  18.            }  

  19.        }  

  20.              


       Step 二、該PackageManager代理對象實則爲ApplicatonPackageManager 對象,該對象是ContextIml的內部類。

[java] view plaincopyprint?

  1. @Override  

  2.         public List<ResolveInfo> queryIntentActivities(Intent intent, int flags) {  

  3.             try {  

  4.                 //mPM對象就是PackageManagerService的客戶端  

  5.                 return mPM.queryIntentActivities(  

  6.                     intent,  

  7.                     intent.resolveTypeIfNeeded(mContext.getContentResolver()),  

  8.                     flags);  

  9.             } catch (RemoteException e) {  

  10.                 throw new RuntimeException("Package manager has died", e);  

  11.             }  

  12.         }  


 

       Step 三、調用服務端PackageManagerService對象的對應方法。該方法位於PackageManagerService.java類中

[java] view plaincopyprint?

  1. public List<ResolveInfo> queryIntentActivities(Intent intent,  

  2.         String resolvedType, int flags) {  

  3.     //是否設置了組件ComponetName 信息  

  4.  ComponentName comp = intent.getComponent();  

  5.     if (comp != null) {  

  6.         List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);  

  7.         ActivityInfo ai = getActivityInfo(comp, flags);  

  8.         if (ai != null) {  

  9.             ResolveInfo ri = new ResolveInfo();  

  10.             ri.activityInfo = ai;  

  11.             list.add(ri);  

  12.         }  

  13.         return list;  

  14.     }  

  15.   

  16.     synchronized (mPackages) {  

  17.         //是否設置了包名  

  18.         String pkgName = intent.getPackage();  

  19.         if (pkgName == null) {  

  20.             //調用mActivities去查詢  

  21.             return (List<ResolveInfo>)mActivities.queryIntent(intent,  

  22.                     resolvedType, flags);  

  23.         }  

  24.         PackageParser.Package pkg = mPackages.get(pkgName);  

  25.         if (pkg != null) {  

  26.             return (List<ResolveInfo>) mActivities.queryIntentForPackage(intent,  

  27.                     resolvedType, flags, pkg.activities);  

  28.         }  

  29.         return null;  

  30.     }  

  31.  }    



     首先、該方法判斷IntentComponentName是否存在,若是存在則爲顯示匹配了,直接返回特定組件相關信息;

     其次、判斷是否設置了包名,即packageName,若是沒有指定包名,則查詢全部的應用程序包去找匹配的組件信息。若是

   指定了packageName,則去指定包下去查找;

     接着,調用特定的類繼續查找。因爲咱們找的是Activity組件信息,所以去ActivityIntentResolver類去查找。

 

     Step 四、調用mActivities自定義類去查找

 

[java] view plaincopyprint?

  1. //調用父類IntentResolver方法去查找  

  2.    public List queryIntent(Intent intent, String resolvedType, int flags) {  

  3.         mFlags = flags;  

  4.         return super.queryIntent(intent, resolvedType,  

  5.             (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0);  

  6.    }  


        該過程只是簡單的調用了父類IntentResolver去查找。

 

     Step5 、進入IntentResolver類去真正的實現查找,該方法爲於IntentResolver.java類中。

 

[java] view plaincopyprint?

  1. public List<R> queryIntent(Intent intent, String resolvedType, boolean defaultOnly) {  

  2.      String scheme = intent.getScheme();  

  3.      //用來保存查找到的組件信息,如Activity等  

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

  5.      //根據關鍵值去特定集合查詢到的一個可能結果  

  6.      ArrayList<F> firstTypeCut = null;  

  7.      ArrayList<F> secondTypeCut = null;  

  8.      ArrayList<F> thirdTypeCut = null;  

  9.      ArrayList<F> schemeCut = null;  

  10.   

  11.      //首先是否制定的數據類型 MimeType  

  12.      // If the intent includes a MIME type, then we want to collect all of  

  13.      // the filters that match that MIME type.  

  14.      if (resolvedType != null) {  

  15.          int slashpos = resolvedType.indexOf('/');  

  16.          if (slashpos > 0) {  

  17.              final String baseType = resolvedType.substring(0, slashpos);  

  18.              if (!baseType.equals("*")) {  

  19.                 //匹配特定的MimeType  

  20.                  if (resolvedType.length() != slashpos+2|| resolvedType.charAt(slashpos+1) != '*') {  

  21.                      firstTypeCut = mTypeToFilter.get(resolvedType);  

  22.                      secondTypeCut = mWildTypeToFilter.get(baseType);  

  23.                  }   

  24.                  //...  

  25.          }  

  26.      }  

  27.      //根據模式去匹配特定的集合  

  28.      if (scheme != null) {  

  29.          schemeCut = mSchemeToFilter.get(scheme);  

  30.      }  

  31.      //可能的話在去匹配Action所在集合  

  32.      if (resolvedType == null && scheme == null && intent.getAction() != null) {  

  33.          firstTypeCut = mActionToFilter.get(intent.getAction());  

  34.      }  

  35.      //對咱們前面經過關鍵字查詢的一個集合,在此循環遍歷匹配,將匹配到的結果保存在finalList集合中  

  36.      if (firstTypeCut != null) {  

  37.          buildResolveList(intent, debug, defaultOnly,  

  38.                  resolvedType, scheme, firstTypeCut, finalList);  

  39.      }  

  40.      if (secondTypeCut != null) {  

  41.          buildResolveList(intent, debug, defaultOnly,  

  42.                  resolvedType, scheme, secondTypeCut, finalList);  

  43.      }  

  44.      if (thirdTypeCut != null) {  

  45.          buildResolveList(intent, debug, defaultOnly,resolvedType, scheme, thirdTypeCut, finalList);  

  46.      }  

  47.      if (schemeCut != null) {  

  48.          buildResolveList(intent, debug, defaultOnly,  

  49.                  resolvedType, scheme, schemeCut, finalList);  

  50.      }  

  51.      //根據IntentFilter的一些優先級進行排序  

  52.      sortResults(finalList);  

  53.   

  54.      return finalList;  

  55.  }  


     buildResolveList()方法的主要做用是將可能的集合在循環遍歷,將匹配的結果值保存在finalList集合中。

   該方法爲於IntentResolver.java類中,方法原型以下:

 

[java] view plaincopyprint?

  1. //經過前面關鍵字查找的可能集合,循環遍歷進行匹配,匹配成功就加入到dest集合中,即finalList集合中  

  2.     private void buildResolveList(Intent intent, boolean debug, boolean defaultOnly,  

  3.             String resolvedType, String scheme, List<F> src, List<R> dest) {  

  4.         Set<String> categories = intent.getCategories();  

  5.   

  6.         final int N = src != null ? src.size() : 0;  

  7.         boolean hasNonDefaults = false;  

  8.         int i;  

  9.         for (i=0; i<N; i++) {  

  10.             F filter = src.get(i);  

  11.             int match;  

  12.             //是否已經加入到匹配結果中去了,不容許重複添加  

  13.             // Do we already have this one?  

  14.             if (!allowFilterResult(filter, dest)) {  

  15.                 continue;  

  16.             }  

  17.             //調用Intent-filter方法去匹配該Intent信息  

  18.             match = filter.match(  

  19.                     intent.getAction(), resolvedType, scheme, intent.getData(), categories, TAG);  

  20.             //匹配成功,就存放在finalList集合中  

  21.             if (match >= 0) {  

  22.                 if (!defaultOnly || filter.hasCategory(Intent.CATEGORY_DEFAULT)) {  

  23.                     //調用子類的newResult()方法去返回一個ResolvInfo對象  

  24.                     final R oneResult = newResult(filter, match);  

  25.                     if (oneResult != null) {  

  26.                         dest.add(oneResult);  

  27.                     }  

  28.                 } else {  

  29.                     hasNonDefaults = true;  

  30.                 }  

  31.             } else {  

  32.                 //...  

  33.             }  

  34.         }  

  35.         //...  

  36.     }     


    這個函數的邏輯判斷以下:


        首先、經過給定的關鍵字去特定集合查詢一個可能的匹配集合,而後將這些集合信息保存在以下集合中:

                          ArrayList<F>firstTypeCut =null;

                          ArrayList<F>secondTypeCut =null;

                          ArrayList<F>thirdTypeCut =null;

                          ArrayList<F>schemeCut =null;

      

       而後、連續四次調用buildResolveList()去進行匹配。每次調用結束後,參數finalList保存的是匹配結果的累加值,因此這

    四次調用過程當中finalList集合包含的結果是一次累加的過程。固然了,四次連續調用buildResolveList()的次序能夠不分前後。

 

       最後、調用sortResults()從匹配集合中進行一些排序等。



         總結:第二部分經過重點介紹了PackageManagerService的功能匹配Intent採用的數據結構和算法,也只是簡單入了下門,希

   望你們能參考源碼,認真理解Intent匹配過程。

相關文章
相關標籤/搜索