Android Action匹配多个Activity信息

      通常情况下,我们都是通过android系统,context.startActivity(intent)方法开启Activity,若intent 中包含action, 当action匹配多个Activity时,系统会跳出选择启动那个Activity界面. 此现象在android系统中是非常常见的。
     但是,若问通过action怎么查找对应的Activity? 可能大部分学者,都感觉很困惑。
    
    我们简单追其原因:
    [1]首先观看UI, 当有多个Activity选择时,会出现"Use a different app"的字符串。
    [2]通过字符串定位,字符串位置:
        frameworks/base/core/res/res/values-en-rAU/strings.xml
       "Use a different app"
 
[3]再通过String ID定位 对应xml布局:
      frameworks/base/core/res/res/layout/resolver_different_item_header.xml
 
[4]通过layout ID 定位对应的Activity.
      frameworks/base/core/java/com/android/internal/app/ResolverActivity.java
 
[5]分析:既然是一个Action对应多个Activity ,那么肯定是一个集合保存数据。果然在
ResolverActivity中发现了适配器 mAdapter.
  [6]有适配器则再次寻找,加载数据的地方。
   frameworks/base/core/java/com/android/internal/app/ResolverActivity.java
 /**
    * Rebuild the list of resolvers. In some cases some parts will need some asynchronous work
    * to complete.
    *
    * @return Whether or not the list building is completed.
    */
         protected boolean rebuildList() {
        ...
        currentResolveList = mUnfilteredResolveList =
                        mResolverListController.getResolversForIntent(shouldGetResolvedFilter(),
                            shouldGetActivityMetadata(),
                              mIntents);

       [7]继续跟踪getResolversForIntent的来源:
     android/frameworks/base/core/java/com/android/internal/app/ResolverListController.java
public List getResolversForIntent(
              boolean shouldGetResolvedFilter,
              boolean shouldGetActivityMetadata,
              List intents) {
            List resolvedComponents = null;
          for (int i = 0, N = intents.size(); i < N; i++) {
               final Intent intent = intents.get(i);
               int flags = PackageManager.MATCH_DEFAULT_ONLY
                       | (shouldGetResolvedFilter ? PackageManager.GET_RESOLVED_FILTER : 0)
                       | (shouldGetActivityMetadata ? PackageManager.GET_META_DATA : 0);
               if (intent.isWebIntent()
                           || (intent.getFlags() & Intent.FLAG_ACTIVITY_MATCH_EXTERNAL) != 0) {
                   flags |= PackageManager.MATCH_INSTANT;
               }
               final List infos = mpm.queryIntentActivities(intent, flags);
                // Remove any activities that are not exported.
               int totalSize = infos.size();
               for (int j = totalSize - 1; j >= 0 ; j--) {
                   ResolveInfo info = infos.get(j);
                   if (info.activityInfo != null && !info.activityInfo.exported) {
                       infos.remove(j);
                   }
               }
               if (infos != null) {
                   if (resolvedComponents == null) {
                       resolvedComponents = new ArrayList<>();
                   }
                   addResolveListDedupe(resolvedComponents, intent, infos);
               }
           }

    public void addResolveListDedupe(List into,
              Intent intent,
               List from) {
           final int fromCount = from.size();
           final int intoCount = into.size();
           for (int i = 0; i < fromCount; i++) {
               final ResolveInfo newInfo = from.get(i);
               boolean found = false;
               // Only loop to the end of into as it was before we started; no dupes in from.
               for (int j = 0; j < intoCount; j++) {
                   final ResolverActivity.ResolvedComponentInfo rci = into.get(j);
                   if (isSameResolvedComponent(newInfo, rci)) {
                       found = true;
                       rci.add(intent, newInfo);
                       break;
                   }
               }
               if (!found) {
                   final ComponentName name = new ComponentName(
                           newInfo.activityInfo.packageName, newInfo.activityInfo.name);
                   final ResolverActivity.ResolvedComponentInfo rci =
                           new ResolverActivity.ResolvedComponentInfo(name, intent, newInfo);
                   rci.setPinned(isComponentPinned(name));
                   into.add(rci);
               }
           }
       }  

通过上面getResolversForIntent()和 addResolveListDedupe(),可以看出, 数据来源于 mpm.queryIntentActivities(), 再看源码mpm 定义 private final PackageManager mpm; 就是一个PackageManager 实例。
[8]接下来寻找PackageManager的queryIntentActivities方法:
     /**
        * Retrieve all activities that can be performed for the given intent.
        *
        * @param intent The desired intent as per resolveActivity().
        * @param flags Additional option flags to modify the data returned. The
        *            most important is {@link #MATCH_DEFAULT_ONLY}, to limit the
        *            resolution to only those activities that support the
        *            {@link android.content.Intent#CATEGORY_DEFAULT}. Or, set
        *            {@link #MATCH_ALL} to prevent any filtering of the results.
        * @return Returns a List of ResolveInfo objects containing one entry for
        *         each matching activity, ordered from best to worst. In other
        *         words, the first item is what would be returned by
        *         {@link #resolveActivity}. If there are no matching activities, an
        *         empty list is returned.
        */
       public abstract List queryIntentActivities(Intent intent,
               @ResolveInfoFlags int flags);


通过注释可以知,此方法从intent查找出所有的activity信息。
 
   [9]根据上面分析,我们可以描述一下完整的通过Action获取Activity集合信息.

         实例演示:


         //获取PackageManager对象
         PackageManager pm = context.getPackageManager();
        //构建Action
        Intent intent = new Intent(StorageManager.ACTION_MANAGE_STORAGE);
        //获取Activity相关信息的集合
        final List infos = pm.queryIntentActivities(intent, 0);
       //遍历集合      
         for (ResolveInfo resolveInfo : infos) {
            String packageName = resolveInfo.activityInfo.getComponentName().getPackageName();
            String className = resolveInfo.activityInfo.getComponentName().getClassName();
            if (tPackageName.equals(packageName) && tClassName.equals(className)) {
                Log.d("TEST", packageName+"/"+className+" contains the action ACTION_MANAGE_STORAGE");
          
            }
        }

你可能感兴趣的:(Action,android)