最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

從Android源碼剖析Intent查詢匹配的實(shí)現(xiàn)

 更新時間:2015年07月30日 16:46:30   作者:低調(diào)小一  
這篇文章主要介紹了從Android源碼剖析Intent查詢匹配的實(shí)現(xiàn),Intent部分的源碼為Java代碼,需要的朋友可以參考下

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

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

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

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

    Explicit Intent:這類Intent明確指明了要找哪個Component。在代碼中可以通過setClassName或者setComponent來鎖定目標(biāo)對象。
    Implicit Intent:這類Intent不明確指明要啟動哪個Component,而是設(shè)置Action、Data、Category讓系統(tǒng)來篩選出合適的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); 
  } 

    但是,從源碼里面去看,發(fā)現(xiàn)setClassName也是借助了ComponentName實(shí)現(xiàn)了Explicit Intent。源碼如下:

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

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

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

    在當(dāng)前應(yīng)用的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); 
  } 

    系統(tǒng)在匹配Implict Intent的過程中,將以Intent Filter列出的3項內(nèi)容為參考標(biāo)準(zhǔn),具體步驟如下:

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


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

  // 處理該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"); 
  } 

    上面代碼中,有兩個比較重要的數(shù)據(jù)結(jié)構(gòu),如下圖所示。

2015730164435391.png (841×306)

結(jié)合代碼和上圖的數(shù)據(jù)結(jié)構(gòu),可知:

    mAcitivitys為ActivityIntentResolver類型,是PKMS的成員變量,用于保存系統(tǒng)中所有與Activity相關(guān)的信息。此數(shù)據(jù)結(jié)構(gòu)內(nèi)部也有一個mActivities變量,它以ComponentName為key,保存PackageParser.Activity對象。
    從APK中解析得到的所有和Acitivity相關(guān)的信息(包括XML中聲明的IntentFilter標(biāo)簽)都由PackageParser.Activity來保存。

    前面代碼中調(diào)用addActivity函數(shù)完成了私有信息的公有化。addActivity函數(shù)的代碼如下:

    

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)) { 
        // 非系統(tǒng)APK的priority必須為0 
        intent.setPriority(0); 
      } 
      addFilter(intent); 
    } 
  } 

    接下來看一下addFilter函數(shù)。函數(shù)源碼如下:

  

 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: "); 
    } 
  } 

    這里又出現(xiàn)了幾種數(shù)據(jù)結(jié)構(gòu),它們的類似都是ArrayMap<String, F[ ]>,其中F為模板參數(shù)。

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

    了解了大概的數(shù)據(jù)結(jié)構(gòu)之后,我們來看一下register_intent_filter的函數(shù)實(shí)現(xiàn):

  

 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函數(shù),明顯是一個函數(shù)重載,我們來看一下這個addFilter的實(shí)現(xiàn):

    

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); 
      } 
    } 
  } 

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

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

  

 @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的真正實(shí)現(xiàn)是在PackageManagerService.java中,函數(shù)代碼如下:

    

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,直接根據(jù)component得到對應(yīng)的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的實(shí)現(xiàn)較為簡單,我們重點(diǎn)來看一下Implict Intent實(shí)現(xiàn)。Implicit Intent調(diào)用了queryIntent方法,我們來看一下queryIntent的實(shí)現(xiàn)代碼:

  

 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); 
  } 

    繼續(xù)跟蹤到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函數(shù)完成了。查詢的匹配實(shí)現(xiàn)我就不貼代碼了,大家自己去查詢看就好了。

   

相關(guān)文章

  • Java程序結(jié)構(gòu)與常量變量難點(diǎn)解析

    Java程序結(jié)構(gòu)與常量變量難點(diǎn)解析

    JAVA的基本結(jié)構(gòu)就是順序結(jié)構(gòu),除非特別指明,否則就按照順序一句一句執(zhí)行順序結(jié)構(gòu)是最簡單的算法結(jié)構(gòu),語句與語句之間,框與框之間是按從上到下的順序進(jìn)行的,它是由若干個依次執(zhí)行的處理步驟組成的,它是任何一個算法都離不開的一種基本算法結(jié)構(gòu)
    2021-10-10
  • SpringBoot綠葉顯示yml和端口問題及解決方法

    SpringBoot綠葉顯示yml和端口問題及解決方法

    今天是解決報錯的一天,首先在操作Springboot中的時候,有些朋友的yml顯示的不是綠葉的圖標(biāo),或者是配置了之后不生效的問題,今天就給大家分享SpringBoot綠葉顯示yml和端口問題,感興趣的朋友一起看看吧
    2023-01-01
  • JavaSE實(shí)戰(zhàn)之酒店訂房系統(tǒng)的實(shí)現(xiàn)

    JavaSE實(shí)戰(zhàn)之酒店訂房系統(tǒng)的實(shí)現(xiàn)

    這篇文章主要為大家詳細(xì)介紹了如何利用JavaSE實(shí)現(xiàn)酒店訂房系統(tǒng),文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)JavaSE開發(fā)有一定的幫助,需要的可以參考一下
    2022-07-07
  • java類加載器和類反射使用示例

    java類加載器和類反射使用示例

    這篇文章主要介紹了java類加載器和類反射使用示例,需要的朋友可以參考下
    2014-03-03
  • 關(guān)于activemq安裝配置以及啟動錯誤的解決

    關(guān)于activemq安裝配置以及啟動錯誤的解決

    這篇文章主要介紹了關(guān)于activemq安裝配置以及啟動錯誤的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • SSH結(jié)合jquery實(shí)現(xiàn)三級聯(lián)動效果

    SSH結(jié)合jquery實(shí)現(xiàn)三級聯(lián)動效果

    這篇文章主要為大家詳細(xì)介紹了SSH結(jié)合jquery實(shí)現(xiàn)三級聯(lián)動效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-01-01
  • JEE與Spring Boot代碼性能比較分析

    JEE與Spring Boot代碼性能比較分析

    JavaEE與Spring Boot其實(shí)很難比較測試,前者適合單體SOA架構(gòu),后者適合微服務(wù),但是還是有好事者把兩者放在一起比較性能。這篇文章主要介紹了JEE與Spring Boot代碼性能比較,需要的朋友可以參考下
    2018-11-11
  • java 將數(shù)據(jù)加載到內(nèi)存中的操作

    java 將數(shù)據(jù)加載到內(nèi)存中的操作

    這篇文章主要介紹了java 將數(shù)據(jù)加載到內(nèi)存中的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • 關(guān)于Java中String創(chuàng)建的字符串對象內(nèi)存分配測試問題

    關(guān)于Java中String創(chuàng)建的字符串對象內(nèi)存分配測試問題

    這篇文章主要介紹了Java中String創(chuàng)建的字符串對象內(nèi)存分配測試,給大家詳細(xì)介紹了在創(chuàng)建String對象的兩種常用方法比較,通過示例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2021-07-07
  • java報錯之springboot3+vue2項目web服務(wù)層報錯總結(jié)

    java報錯之springboot3+vue2項目web服務(wù)層報錯總結(jié)

    java入門學(xué)習(xí),隨手記錄一下開發(fā)過程中產(chǎn)生的報錯,有些錯誤是網(wǎng)上搜索再加上自己嘗試,隨手引用了一些其他人的記錄,也是留給自己看的,或是希望能對其他初學(xué)者有幫助

    2023-06-06

最新評論

泉州市| 卢氏县| 阜新| 栾川县| 六安市| 绥江县| 永春县| 北流市| 德惠市| 杨浦区| 林周县| 云林县| 沈阳市| 中阳县| 吴桥县| 信丰县| 十堰市| 胶州市| 道孚县| 黄陵县| 拉孜县| 定安县| 余姚市| 龙江县| 马公市| 松滋市| 灵丘县| 自治县| 烟台市| 和静县| 桐柏县| 库尔勒市| 霸州市| 雷山县| 安徽省| 达拉特旗| 澎湖县| 昌黎县| 萝北县| 泗洪县| 崇信县|