亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Java > 正文

從Android源碼剖析Intent查詢匹配的實現

2019-11-26 15:02:38
字體:
來源:轉載
供稿:網友

前言
    這篇文章主要是介紹一下Android Intent,并且從Android源碼的角度對Intent查詢匹配過程進行分析。

Intent介紹
    Intent的中文是“意圖”的意思,而意圖是一個非常抽象的概念,那么在Android的編碼設計中,如何實例化意圖呢?因此Android系統明確指定一個Intent可由兩方面屬性來衡量。

    主要屬性:包括Action和Data。其中Action用于表示該Intent所表達的動作意圖,Data用于表示該Action所操作的數據。
    次要屬性:包括Category、Type、Component和Extras。其中Category表示類別,Type表示數據的MIME類型,Component可用于指定特定的Intent的響應者(例如指定intent為某個包下的某個class類),Extras用于承載其他的信息。

    Android系統中主要有兩種類型的Intent,顯示Intent(Explicit Intent)和隱式Intent(Implicit Intent)。

    Explicit Intent:這類Intent明確指明了要找哪個Component。在代碼中可以通過setClassName或者setComponent來鎖定目標對象。
    Implicit Intent:這類Intent不明確指明要啟動哪個Component,而是設置Action、Data、Category讓系統來篩選出合適的Component。

    接下來,寫兩個代碼示例,來介紹一下Explicit Intent和Implict Inent。首先是Explicit Intent:

   

 private void startExplicitIntentWithComponent() {     Intent intent = new Intent();     ComponentName component = new ComponentName("com.example.photocrop", "com.example.photocrop.MainActivity");     intent.setComponent(component);     startActivity(intent);   }      private void startExplicitIntentWithClassName() {     Intent intent = new Intent();     intent.setClassName("com.example.photocrop", "com.example.photocrop.MainActivity");     startActivity(intent);   } 

    但是,從源碼里面去看,發現setClassName也是借助了ComponentName實現了Explicit Intent。源碼如下:

  public Intent setClassName(String packageName, String className) {     mComponent = new ComponentName(packageName, className);     return this;   } 

    然后,在給出一個Implict Intent的代碼示例。我這里用一個Activity標注一些Intent Filter為例,然后在寫一個Intent用于啟動它。

  <activity      android:name=".SendIntentType">     <intent-filter >       <action android:name="justtest"/>       <category android:name="justcategory"/>     </intent-filter>   </activity> 

    在當前應用的AndroidManifest.xml中,給SendIntentType類增加了intent-filter,action的名字為“justtest”,category的名字為“justcategory”。啟動該Activity的代碼如下:

  private void startImplictIntent() {     Intent intent = new Intent();     intent.setAction("justaction");     intent.addCategory("justcategory");     startActivity(intent);   } 

    系統在匹配Implict Intent的過程中,將以Intent Filter列出的3項內容為參考標準,具體步驟如下:

  •     首先匹配IntentFilter的Action,如果Intent設置的action不滿足IntentFilter的Action,則匹配失敗。如果IntentFilter未設定Action或者設定的Action相同,則匹配成功。
  •     然后檢查IntentFilter的Category,匹配方法同Action的匹配相同,唯一例外的是當Category為CATEGORY_DEFAULT的情況。
  •     最后檢查Data。


Activityi信息的管理
    從上面的分析可以看出,系統的匹配Intent的過程中,首先需要管理當前系統中所有Activity信息。Activity的信息是PackageManagerService在掃描APK的時候進行收集和管理的。相關源碼如下:

  // 處理該package的activity信息   N = pkg.activities.size();   r = null;   for (i = 0; i < N; i++) {     PackageParser.Activity a = pkg.activities.get(i);     a.info.processName = fixProcessName(pkg.applicationInfo.processName, a.info.processName,         pkg.applicationInfo.uid);     mActivities.addActivity(a, "activity");   } 

    上面代碼中,有兩個比較重要的數據結構,如下圖所示。

2015730164435391.png (841×306)

結合代碼和上圖的數據結構,可知:

    mAcitivitys為ActivityIntentResolver類型,是PKMS的成員變量,用于保存系統中所有與Activity相關的信息。此數據結構內部也有一個mActivities變量,它以ComponentName為key,保存PackageParser.Activity對象。
    從APK中解析得到的所有和Acitivity相關的信息(包括XML中聲明的IntentFilter標簽)都由PackageParser.Activity來保存。

    前面代碼中調用addActivity函數完成了私有信息的公有化。addActivity函數的代碼如下:

    

public final void addActivity(PackageParser.Activity a, String type) {     final boolean systemApp = isSystemApp(a.info.applicationInfo);     mActivities.put(a.getComponentName(), a);     final int NI = a.intents.size();     for (int j = 0; j < NI; j++) {       PackageParser.ActivityIntentInfo intent = a.intents.get(j);       if (!systemApp && intent.getPriority() > 0 && "activity".equals(type)) {         // 非系統APK的priority必須為0         intent.setPriority(0);       }       addFilter(intent);     }   } 

    接下來看一下addFilter函數。函數源碼如下:

  

 public void addFilter(F f) {     // mFilters保存所有IntentFilter信息     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: ");     }   } 

    這里又出現了幾種數據結構,它們的類似都是ArrayMap<String, F[ ]>,其中F為模板參數。

  •     mSchemeToFilter:用于保存uri中與scheme相關的IntentFilter信息。
  •     mActionToFilter:用于保存僅設置Action條件的IntentFilter信息。
  •     mTypedActionToFilter:用于保存既設置了Action又設置了Data的MIME類型的IntentFilter信息。

    了解了大概的數據結構之后,我們來看一下register_intent_filter的函數實現:

  

 private final int register_intent_filter(F filter, Iterator<String> i,       ArrayMap<String, F[]> dest, String prefix) {     if (i == null) {       return 0;     }        int num = 0;     while (i.hasNext()) {       String name = i.next();       num++;       addFilter(dest, name, filter);     }     return num;   } 

    然后又是一個addFilter函數,明顯是一個函數重載,我們來看一下這個addFilter的實現:

    

private final void addFilter(ArrayMap<String, F[]> map, String name, F filter) {     F[] array = map.get(name);     if (array == null) {       array = newArray(2);       map.put(name, array);       array[0] = filter;     } else {       final int N = array.length;       int i = N;       while (i > 0 && array[i-1] == null) {         i--;       }       if (i < N) {         array[i] = filter;       } else {         F[] newa = newArray((N*3)/2);         System.arraycopy(array, 0, newa, 0, N);         newa[N] = filter;         map.put(name, newa);       }     }   } 

    其實代碼還是很簡單的,如果F數組存在,則判斷容量,不夠則擴容,夠的話就找到位置插入。如果F數組不存在,則創建一個容量為2的數組,將0號元素賦值為該filter。

Intent匹配查詢分析
    客戶端通過ApplicationPackageManager輸出的queryIntentActivities函數向PackageManagerService發起一次查詢請求,代碼如下:

  

 @Override   public List<ResolveInfo> queryIntentActivities(Intent intent,                           int flags) {     return queryIntentActivitiesAsUser(intent, flags, mContext.getUserId());   }      /** @hide Same as above but for a specific user */   @Override   public List<ResolveInfo> queryIntentActivitiesAsUser(Intent intent,                           int flags, int userId) {     try {       return mPM.queryIntentActivities(         intent,         intent.resolveTypeIfNeeded(mContext.getContentResolver()),         flags,         userId);     } catch (RemoteException e) {       throw new RuntimeException("Package manager has died", e);     }   } 

    可以看到,queryIntentActivities的真正實現是在PackageManagerService.java中,函數代碼如下:

    

public List<ResolveInfo> queryIntentActivities(Intent intent, String resolvedType, int flags, int userId) {     if (!sUserManager.exists(userId))       return Collections.emptyList();     enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "query intent activities");     ComponentName comp = intent.getComponent();     if (comp == null) {       if (intent.getSelector() != null) {         intent = intent.getSelector();         comp = intent.getComponent();       }     }        if (comp != null) {       // Explicit的Intent,直接根據component得到對應的ActivityInfo       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) {         // Implicit Intent         return mActivities.queryIntent(intent, resolvedType, flags, userId);       }       final PackageParser.Package pkg = mPackages.get(pkgName);       if (pkg != null) {         // 指定了包名的Intent         return mActivities.queryIntentForPackage(intent, resolvedType, flags, pkg.activities, userId);       }       return new ArrayList<ResolveInfo>();     }   } 

    可以看到,Explicit Intent的實現較為簡單,我們重點來看一下Implict Intent實現。Implicit Intent調用了queryIntent方法,我們來看一下queryIntent的實現代碼:

  

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

    繼續跟蹤到IntentResolver.java的queryIntent方法,源碼如下:

    

public List<R> queryIntent(Intent intent, String resolvedType, boolean defaultOnly,       int userId) {     String scheme = intent.getScheme();        ArrayList<R> finalList = new ArrayList<R>();        // 最多有4輪匹配操作     F[] firstTypeCut = null;     F[] secondTypeCut = null;     F[] thirdTypeCut = null;     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);             secondTypeCut = mWildTypeToFilter.get(baseType);           } else {             // We can match anything with our base type.             firstTypeCut = mBaseTypeToFilter.get(baseType);             secondTypeCut = mWildTypeToFilter.get(baseType);           }           // Any */* types always apply, but we only need to do this           // if the intent type was not already */*.           thirdTypeCut = mWildTypeToFilter.get("*");         } 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 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 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());     }        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);        return finalList;   } 

    具體的查詢匹配過程是由buildResolveList函數完成了。查詢的匹配實現我就不貼代碼了,大家自己去查詢看就好了。

   

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产精品网站入口| 欧美专区国产专区| 在线播放国产精品| 欧美最近摘花xxxx摘花| 亚洲欧美日韩高清| 国产成人在线一区二区| 欧美成aaa人片免费看| 国产福利视频一区二区| 欧美乱大交xxxxx另类电影| 日韩免费av片在线观看| 亚洲第一页中文字幕| 午夜精品美女自拍福到在线| 国产精品一区二区电影| 亚洲精品网站在线播放gif| 成人黄色大片在线免费观看| 欧美电影电视剧在线观看| 国产精品丝袜白浆摸在线| 亚洲精品国产品国语在线| 日韩欧美国产网站| 国产欧美精品一区二区三区介绍| 日韩欧美主播在线| 久久99热这里只有精品国产| 日韩在线免费观看视频| 日韩电影视频免费| 欧美最猛性xxxxx(亚洲精品)| 激情懂色av一区av二区av| 国产日韩换脸av一区在线观看| 国产日韩欧美日韩| 欧美激情极品视频| 国产精品视频免费观看www| 成人欧美在线视频| 奇米成人av国产一区二区三区| 麻豆精品精华液| 亚洲天堂av网| 尤物yw午夜国产精品视频明星| 亚洲成av人片在线观看香蕉| 色综合伊人色综合网| 欧美国产高跟鞋裸体秀xxxhd| 欧美在线不卡区| 日韩精品免费视频| 91国产视频在线| 欧美成人午夜视频| 亚洲第一男人av| 日韩最新免费不卡| 亚洲国产成人在线播放| 亚洲综合在线中文字幕| 日韩欧美高清在线视频| 亚洲国产精品嫩草影院久久| 国产99久久精品一区二区永久免费| 亚洲第一免费播放区| 亚洲色图综合久久| 成人在线免费观看视视频| 国产婷婷成人久久av免费高清| 91国产高清在线| 另类视频在线观看| 国产精品久久久久久亚洲影视| 欧美激情一区二区久久久| 亚洲欧洲日本专区| 国产精品老女人视频| 亚洲男人天堂九九视频| 狠狠色狠狠色综合日日小说| 国产精品男人爽免费视频1| 国产91精品高潮白浆喷水| 亚洲欧美在线一区二区| 日本一本a高清免费不卡| 久久久久久高潮国产精品视| 成人精品视频99在线观看免费| 色婷婷综合久久久久中文字幕1| 国产精品扒开腿爽爽爽视频| 成人黄色网免费| 日韩不卡中文字幕| 欧美精品激情在线| 亚洲一区二区三区xxx视频| 国产精品福利观看| 欧美午夜丰满在线18影院| 国产精品美女www| 欧美精品videosex牲欧美| 97热在线精品视频在线观看| 国产婷婷97碰碰久久人人蜜臀| 久久久成人精品| 亚洲v日韩v综合v精品v| 欧美第一淫aaasss性| 久久久爽爽爽美女图片| 日韩中文字幕在线观看| 北条麻妃久久精品| 国产成人综合精品| 亚洲精品国产品国语在线| 欧美老女人在线视频| 亚洲精品国产综合久久| 国产99久久精品一区二区 夜夜躁日日躁| 久久精品中文字幕一区| 91青草视频久久| 久久97久久97精品免视看| 久久久久久高潮国产精品视| 国产大片精品免费永久看nba| 尤物九九久久国产精品的分类| 亚洲精品一区中文| 色av中文字幕一区| 亚洲香蕉成人av网站在线观看| 日韩中文字幕网址| 色悠悠久久88| 欧美激情xxxx| 中文字幕亚洲图片| 国产区亚洲区欧美区| 国产一区二区三区毛片| 毛片精品免费在线观看| 日韩av免费观影| 亚洲字幕在线观看| 亚洲综合中文字幕在线观看| 成人有码在线播放| 久久人人爽人人爽人人片亚洲| 国产大片精品免费永久看nba| 国产精品久久9| 久久久久久91| 欧美视频在线观看 亚洲欧| 亚洲一区二区福利| 欧美大肥婆大肥bbbbb| 中文字幕日韩在线观看| 色婷婷亚洲mv天堂mv在影片| 国产精品国产三级国产aⅴ浪潮| 欧美专区第一页| 欧美激情乱人伦| 亚洲福利视频久久| 精品动漫一区二区三区| 亚洲欧美国产va在线影院| 国产一区二中文字幕在线看| 亚洲欧美激情视频| 亚洲大胆人体av| 久久久久久国产精品| 国内免费久久久久久久久久久| 中文字幕欧美日韩在线| 俺去亚洲欧洲欧美日韩| 欧美黑人一级爽快片淫片高清| 久久夜色精品国产欧美乱| 久久伊人精品天天| 久国内精品在线| 亚洲男人天堂手机在线| 日韩欧美黄色动漫| 日韩免费在线观看视频| 亚洲精品国产精品国自产在线| 日韩在线观看免费高清完整版| 45www国产精品网站| 主播福利视频一区| 国产精品伦子伦免费视频| 国产精品久久久久久久久久99| 日韩国产欧美区| 亚洲视频电影图片偷拍一区| 亚洲欧美中文日韩在线| 国模吧一区二区三区| 中文字幕精品在线| 欧美三级欧美成人高清www| 国产欧美 在线欧美| 日韩欧美亚洲范冰冰与中字| 麻豆一区二区在线观看| 色yeye香蕉凹凸一区二区av| 亚洲色图第一页| 91精品啪在线观看麻豆免费| 久久午夜a级毛片| 亚洲变态欧美另类捆绑| 国产成人精品在线| 国产精品视频久久| 国产欧美日韩丝袜精品一区| 亚洲国产91色在线| 亚洲最新在线视频|