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

關於Intent以及IntentFilter的基本知識,大家可以參閱如下資料,

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

                       其中文翻譯如下:

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

 

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

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

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

 

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

 

       想當初我看Intent相關知識時,對Intent、IntentFilter的理解就很差勁,總覺得系統定義了一個Intent,爲何還要整理個

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

   

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


        *  它們是什麼 ?
 
       *  它們的區別在哪兒 ?
 
   事實上,這兩個問題可以歸納爲Intent和Intent的主要功能是什麼 ? 大家可以先捫心自問下,看看你的掌握程度如何 ?
 
   我的理解如下:
 
       * Intent :   主要功能是根據特定的條件找到匹配的組件,繼而對該組件執 行一些操作。比如執行startActivity()時,系統
              首先要找到特定的Activity組件,然後執行onCreate()方法;startService()也得先找的特定的Service組件,然後執行  
               onCreate()或者onStart()方法 。
 
      * IntentFilter :主要功能是爲某個組件向系統註冊一些特性(當然一個組件可以註冊多個IntentFilter),以便Intent找到對應
             的組件。
 
 

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

 
      通過前面對Intent以及IntentFilter的分析,我們很容易在語意上得出它們其實是個前後關係
 
         * IntentFilter在前:任何一個組件必須先通過IntentFilter註冊。
 
        * Intent 在後       :根據特定信息,找到之前以及註冊過的組件。
 
 
  源碼分析:
 
    Intent類源碼(部分) 路徑位於:\frameworks\base\core\java\android\content\Intent.java

  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

  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

屬性都是集合類型的。從這方面思考,更可以加深我們的理解。

 

 三、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解析過程時也會用到。 具體邏輯在代碼中進行了說明。

  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. }  


    這部分我們重點講解的知識點有如下:
 
           1、Intent以及IntentFilter的主要職能
           2、Intent與IntentFilter的關係
           3、匹配規則說明
 
 

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

  
       在繼續看本部分之前,希望您最好對PackageManagerService-----程序包管理服務有一定的認知(沒有也是OK的咯)。
  可以參考下面這篇問題去看看PackageManagerService的功能和相關流程。

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

    一、引入PackageManager

           我們知道Android源碼總是貼心的(不知道有沒有10086貼心),它對外提供了很多借口供應用程序調用,例如AudioManger

    (音頻管理)、TelephoneManger(電話管理)、同樣也提供了一個包管理-----PackageManager,通過它我們可以、獲取應用

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

 

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

 

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

          前面所說PackageManager不過是個傀儡,所有相關的操作都是由PackageManagerService 完成的。這兒我們簡單的

      分析下PackageManagerService 的特性:

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

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

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

                 它會掃描這兩個目錄:

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

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

          掃描完成後,於是所有的信息結構就構建了。PackageManagerService 的四個重要屬性如下:

  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類的內部類,顯然該類存在於用戶空間中。
 
       源代碼(部分)如下:
 
  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的簡單關係如下:

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

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

 
       毫無疑問,保存所有信息是一項很複雜的工程,在具體講解匹配過程時,我們先看看系統爲了保存這些結構定義的一些
   數據結構。
           
       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圖表示如下:  

                                                  

 

   

     2、Intent解析採用的算法

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

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

        假設一個女人決定參加一個相親節目(大家可以理解成《非誠勿擾》),然後她向主辦方提出如下條件:       

                1、身高 ?     175cm以上 ;

                        2、 財富 ?     100萬 ;

                        3、 學歷 ?     本科以上 ;

                           ……

 

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

 

       最開始,該經理是這麼想的,我把所有男的都給遍歷一遍,肯定把滿足這些條件的男人給揪出來。他找啊找,覺得這麼找下去

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

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


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


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

                   


 

       可能大家對這種根據關鍵值分類的好處不能一目瞭然。我們舉個一般例子吧:

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


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

       最後,對不同的分類中查詢的結果進行組合重新排列下,即可得到我們的滿足該女性的要求。

          

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

   Schema字段去進行分類。分類之後的集合大致如下:


                               


       於是在進行具體匹配時,我們只是需要根據關鍵值從不同集合中獲取即可。


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

  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 1、獲取PackageManager代理對象,調用該方法:

  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 2、該PackageManager代理對象實則爲ApplicatonPackageManager 對象,該對象是ContextIml的內部類。

  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 3、調用服務端PackageManagerService對象的對應方法。該方法位於PackageManagerService.java類中

  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 4、調用mActivities自定義類去查找

 

  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類中。

 

  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類中,方法原型如下:

 

  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匹配過程。


轉載出處 :http://blog.csdn.net/qinjuning

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章