程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 從Android源碼分析Intent查詢婚配的完成

從Android源碼分析Intent查詢婚配的完成

編輯:關於JAVA

從Android源碼分析Intent查詢婚配的完成。本站提示廣大學習愛好者:(從Android源碼分析Intent查詢婚配的完成)文章只能為提供參考,不一定能成為您想要的結果。以下是從Android源碼分析Intent查詢婚配的完成正文


媒介
    這篇文章重要是引見一下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"); 
  } 

    下面代碼中,有兩個比擬主要的數據構造,以下圖所示。

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

    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函數完成了。查詢的婚配完成我就不貼代碼了,年夜家本身去查詢看就行了。

   

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved