Android Framework 包管理子系统(05)intent查询组件

112 篇文章 83 订阅

该系列文章总纲链接:专题分纲目录 Android Framework 包管理子系统


本章关键点总结 & 说明:

导图是不断迭代的,这里主要关注➕ 查询intent组件部分。主要对PkgMS查询组件的流程进行分析,通过intent找到对应的组件并返回。简介了intent和intentFilter,说明了查询的接口,同时对queryIntentActivities接口进行流程解读。

1 intent 和 intentFilter简介

1.1 intent简介

Intent中文是“意图”的意思,它是Android系统中很常用的概念;个人认为 这种基本思想源于对生活的抽象;人与人沟通用的是语言,表达的是意图,比如:

startActivity(Intent intent)

startService(Intent intent)

bindService(Intent intent)

sendBrodcast(Intent intent)

之所以可以用使用intent表达意图,是因为只要用特定的某种格式就可以精确的表达“意图”,因此格式的设定非常关键,intent的属性分类如下:

  1. 启动类:有ComponentName(显式),Action(隐式),Category(隐式)。
  2. 传值类:有Data(隐式),Type(隐式),Extra(隐式、显式)。
  3. 启动模式类:有Flag,这意味着可以根据flag做不同的处理。

我们对比我们平时的沟通模式,启动类 对应 动词,传值类 对应 宾语,加起来就是一个动宾结构,而这就是语言中最核心的结构,“主谓宾” 是我们表达意图最常用、也是最熟悉的方式。那么根据是否有主语决定了 是显示调用还是隐式调用。而这也是intent分类的根源所在(以上仅为自己的知识积累所做的一个概述),intent的分类如下:

Explicit Intents(显示):这类Intent明确指明 主语。在代码中通过setComponent或setClass来锁定目标对象。处理这种Intent高效

Implicit Intents(隐示):这一类Intents只指明动宾关系,主语是一个范围。对于这类意图,处理相对复杂。

1.2 intentFilter简介

在与人沟通的模型中,找合适的人(与谁沟通)是一个很关键的事情,比如找对象、找合作伙伴、筛选简历等等,首先我们会给出筛选的原则,之后会根据筛选原则去和遇到的每个人去匹配,而在Android中这项工作被称为Intent Resolution。在做匹配工作时,将以Intent Filter 列出的3项内容为参考 标准,具体步骤如下:

  1. 匹配IntentFilter的Action,如果Intent设置的Action不满足IntentFilter的Action,则匹配失败。如果IntentFilter未设定Action,则匹配成功。
  2. 检查IntentFilter的Category,匹配方法同Action的匹配,唯一有些例外的是Category为CATEGORY_DEFAULT的情况。
  3. 检查Data。Data的匹配过程比较繁琐,因为它和IntentFilter设置的Data内容有关

这里IntentFilter中的Data可以包括两个内容:

  1. URI:完整格式为“scheme://host:port/path”,包含4个部分,scheme、host、port和path。其中host和port合起来标示URI   authority,指明服务器网络地址(IP & port)。由于URI最多可包含4个部分,因此要根据情况相应部分做匹配检查。
  2. Date type:指定数据的MIME类型(注意:URI中也可以携带数据的类型信息,所以在匹配过程中,还需要考虑URI中指定的数据类型)

2 通过intent查询组件

2.1 查询基础

PkgMS中很重的一项工作就是根据intent来查询处理Intent的续组件信息,处理Intent的查询接口如下:

queryIntentActivities
queryIntentServices
queryIntentReceivers
queryIntentContentProviders

系统中响应某个intent的组件可能有多个,因此返回值是一个列表,android系统中用ResolveInfo类来表示所有组件,ResolveInfo定义如下:

public class ResolveInfo implements Parcelable {
    private static final String TAG = "ResolveInfo";
    public ActivityInfo activityInfo;
    public ServiceInfo serviceInfo;
    public ProviderInfo providerInfo;
    public IntentFilter filter;
	//...
}

2.2 queryIntentActivities案例

几种查询组件的方式类似,这里以queryIntentActivities为例来分析查询过程,代码如下:

@Override
public List<ResolveInfo> queryIntentActivities(Intent intent,
        String resolvedType, int flags, int userId) {
    if (!sUserManager.exists(userId)) return Collections.emptyList();
    //检查调用接口的用户权限
    enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "query intent activities");
    ComponentName comp = intent.getComponent();
    if (comp == null) {
        if (intent.getSelector() != null) {
            intent = intent.getSelector(); 
            comp = intent.getComponent();
        }
    }

    if (comp != null) {
        //如果指定饿模块和组名,则只有一个匹配项
        final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
        //通过模块信息得到ActivityInfo
        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) {//如果intent中没有包名,则在系统中查找
            List<CrossProfileIntentFilter> matchingFilters =
                    getMatchingCrossProfileIntentFilters(intent, resolvedType, userId);
            // Check for results that need to skip the current profile.
            ResolveInfo resolveInfo  = querySkipCurrentProfileIntents(matchingFilters, intent,
                    resolvedType, flags, userId);
            if (resolveInfo != null) {
                List<ResolveInfo> result = new ArrayList<ResolveInfo>(1);
                result.add(resolveInfo);
                return result;
            }
            //在当前profile中查找
            resolveInfo = queryCrossProfileIntents(
                    matchingFilters, intent, resolvedType, flags, userId);

            // Check for results in the current profile.
            List<ResolveInfo> result = mActivities.queryIntent(
                    intent, resolvedType, flags, userId);
            if (resolveInfo != null) {
                result.add(resolveInfo);
                Collections.sort(result, mResolvePrioritySorter);
            }
            return result;
        }
        //如果intent中有包名,则在指定的包中查找。
        final PackageParser.Package pkg = mPackages.get(pkgName);
        if (pkg != null) {
            return mActivities.queryIntentForPackage(intent, resolvedType, flags,
                    pkg.activities, userId);
        }
        return new ArrayList<ResolveInfo>();
    }
}

该方法会根据Intent的信息来分别处理。整体来说,分三步处理如下:

  1. 如果intent中指明Component,则直接查询该Component对应的ActivityInfo,执行getActivityInfo后直接返回ActivityInfo。这是最快的方式。
  2. 如果只有包名,则调用queryIntentForPackage来,根据Package名找到该Package,然后再从该Package包含的Activities中进行匹配查询。
  3. 如果前面条件都不满足,则调用QueryIntent来搜索所有的安装包,也是最慢的查询方式。

queryIntentActivities的函数实现,目的就是进行Intent匹配查询。

 

 

 

 

 

 

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

图王大胜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值