激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服務器之家 - 編程語言 - JAVA教程 - 從Android源碼剖析Intent查詢匹配的實現

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

2019-12-30 14:15低調小一 JAVA教程

這篇文章主要介紹了從Android源碼剖析Intent查詢匹配的實現,Intent部分的源碼為Java代碼,需要的朋友可以參考下

前言
    這篇文章主要是介紹一下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:

   

?
1
2
3
4
5
6
7
8
9
10
11
12
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。源碼如下:

?
1
2
3
4
public Intent setClassName(String packageName, String className) {
  mComponent = new ComponentName(packageName, className);
  return this;
}

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

?
1
2
3
4
5
6
7
<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的代碼如下:

?
1
2
3
4
5
6
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的時候進行收集和管理的。相關源碼如下:

?
1
2
3
4
5
6
7
8
9
// 處理該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");
}

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

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

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

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

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

    

?
1
2
3
4
5
6
7
8
9
10
11
12
13
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函數。函數源碼如下:

  

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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的函數實現:

  

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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的實現:

    

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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發起一次查詢請求,代碼如下:

  

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@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中,函數代碼如下:

    

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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的實現代碼:

  

?
1
2
3
4
5
6
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方法,源碼如下:

    

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
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在线不卡免费 | 免费一级特黄毛片视频 | 99精品国产小情侣高潮露脸在线 | 成人在线观看一区 | 欧美黑大粗硬毛片视频 | 99视频在线观看视频 | 精品亚洲在线 | 国产日产精品久久久久快鸭 | 欧美一级黄视频 | 成人三级在线播放 | 在线a亚洲视频播放在线观看 | 成人区一区二区 | 欧美成人一区二区三区 | 日韩毛片免费观看 | 超久久 | 免费国产网站 | 久草手机在线 | 视频一区二区久久 | 久久艹国产精品 | 久国久产久精永久网页 | 午夜视频在线观看免费视频 | 日本不卡视频在线观看 | 欧美一级一区二区三区 | 亚洲福利在线视频 | 国产久草视频在线 | 精品国产网站 | 特级西西444www大精品视频免费看 | 欧美交在线 | 性 毛片| 国产精品1区2区在线观看 | 91看片王| av电影在线网 | 在线高清中文字幕 | 久草在线资源观看 | 日韩精品一区二区三区中文 |