• PendingIntent


    PendingIntent 可以看作是对 Intent 的一个封装,但它不是立即执行某个行为,而是满足某些条件或者触发某些事件后才执行指定的行为。

    获取 PendingIntent 的方法有以下三种,分别是通过 Activity、Service、BroadcastReceiver 获取:

    • 通过 getActivity 系列方法从系统中获取一个用于启动 Activity 的 PendingIntent 对象;
    • 通过 getService 系列方法从系统中获取一个用于启动 Service 的 PendingIntent 对象;
    • 通过 getBroadcast 系列方法从系统中获取一个用于启动 BroadcastReceiver 的 PendingIntent 对象;

    以下是相关源码:

    public final class PendingIntent implements Parcelable {
        public static PendingIntent getActivity(Context context, int requestCode,
                 Intent intent, @Flags int flags) {
            return getActivity(context, requestCode, intent, flags, null);
        }
    
        public static PendingIntent getActivity(Context context, int requestCode,
                @NonNull Intent intent, @Flags int flags, @Nullable Bundle options) {
            String packageName = context.getPackageName();
            String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
                context.getContentResolver()) : null;
            try {
                intent.migrateExtraStreamToClipData(context);
                intent.prepareToLeaveProcess(context);
                IIntentSender target =
                    ActivityManager.getService().getIntentSenderWithFeature(
                    ActivityManager.INTENT_SENDER_ACTIVITY, packageName,
                    context.getAttributionTag(), null, null, requestCode, new Intent[] { intent },
                    resolvedType != null ? new String[] { resolvedType } : null,
                    flags, options, context.getUserId());
                return target != null ? new PendingIntent(target) : null;
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
    
        public static PendingIntent getActivities(Context context, int requestCode,
                @NonNull Intent[] intents, @Flags int flags) {
            return getActivities(context, requestCode, intents, flags, null);
        }
    
        public static PendingIntent getActivities(Context context, int requestCode,
                    @NonNull Intent[] intents, @Flags int flags, @Nullable Bundle options) {
            String packageName = context.getPackageName();
            String[] resolvedTypes = new String[intents.length];
            for (int i=0; i<intents.length; i++) {
                intents[i].migrateExtraStreamToClipData(context);
                intents[i].prepareToLeaveProcess(context);
                resolvedTypes[i] = intents[i].resolveTypeIfNeeded(context.getContentResolver());
            }
            try {
                IIntentSender target =
                    ActivityManager.getService().getIntentSenderWithFeature(
                    ActivityManager.INTENT_SENDER_ACTIVITY, packageName,
                    context.getAttributionTag(), null, null, requestCode, intents, resolvedTypes,
                    flags, options, context.getUserId());
                return target != null ? new PendingIntent(target) : null;
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
    
        public static PendingIntent getService(Context context, int requestCode,
                    @NonNull Intent intent, @Flags int flags) {
            return buildServicePendingIntent(context, requestCode, intent, flags,
                              ActivityManager.INTENT_SENDER_SERVICE);
        }
    
        public static PendingIntent getBroadcast(Context context, int requestCode,
                     Intent intent, @Flags int flags) {
            return getBroadcastAsUser(context, requestCode, intent, flags, context.getUser());
        }
    }
    
    • 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

    对于参数 flag 可以有以下状态:

    • FLAG_NO_CREATE:如果当前系统中已经存在一个相匹配的 PendingIntent 对象,将不进行创建,如果不存在,也不会创建该 PendingIntent 对象,而是直接返回 NULL;
    • FLAG_ONE_SHOT:该 PendingIntent 只作用一次,在该 PendingIntent 对象通过 send 方法触发过后,PendingIntent 将自动调用 cancel 进行销毁。如果再次调用 send 方法的话,系统将会返回一个 SendIntentException
    • FLAG_CANCEL_CURRENT:如果当前系统中已经存在一个相匹配的 PendingIntent,那么,将已有的 PendingIntent 取消,再重新生成一个 PendingIntent 对象;
    • FLAG_UPDATE_CURRENT:如果系统中有一个相匹配的 PendingIntent,系统将使用该 PendingIntent 对象,但是,会使用新的 Intent.Extra 来更新之前的 PendingIntent 中的 Intent 数据;

    备注:两个 PendingIntent 对等指它们的 operation 一样,且它们的 Intent 的 action、data、categories、components 和 flags 都一样,但它们的 Intent 的 Extra 可以不一样。

    PendingIntent 的匹配规则:如果两个 PendingIntent 的 Intent 相同并且 requestCode 也相同,那么这两个 PendingIntent 是相匹配的。

    Intent 的匹配规则:如果两个 Intent 的 ComponentName 和 intent-filter 都相同,那么这两个 Intent 是相同的,Extras 不参加 Intent 的匹配过程。以下是 Intent.filterEquals 方法:

    public class Intent implements Parcelable, Cloneable {
    
        /* 
         * Determine if two intents are the same for the purposes of intent resolution (filtering). Thatis,  
         * if their action, data, type, identity, class, and categories are the same. This does not compare 
         * any extra data included in the intents. Note that technically when actually matching against an 
         * IntentFilter the identifier is ignored, while here it is directly compared for equality like the 
         * other fields.
         * Params:
         * other – The other Intent to compare against.
         * Returns:
         * Returns true if action, data, type, class, and categories are the same.
         */
        public boolean filterEquals(Intent other) {
            if (other == null) {
                return false;
            }
            if (!Objects.equals(this.mAction, other.mAction)) return false;
            if (!Objects.equals(this.mData, other.mData)) return false;
            if (!Objects.equals(this.mType, other.mType)) return false;
            if (!Objects.equals(this.mIdentifier, other.mIdentifier)) return false;
            if (!(this.hasPackageEquivalentComponent() && other.hasPackageEquivalentComponent())
                && !Objects.equals(this.mPackage, other.mPackage)) {
                return false;
            }
            if (!Objects.equals(this.mComponent, other.mComponent)) return false;
            if (!Objects.equals(this.mCategories, other.mCategories)) return false;
    
            return true;
        }
    }
    
    • 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

    如果是 Android 12 及以上的系统,要求为每个创建的 PendingIntent 对象指定可变性,这样做可以提高应用的安全性。如需声明 PendingIntent 对象是否可变,分别使用 PendingIntent.FLAG_MUTABLE 或 PendingIntent.FLAG_IMMUTABLE 标志。如果在不设置任何可变标志的情况下创建 PendingIntent 对象,系统会抛出 IllegalArgumentException。

    在 Android 12 之前的版本中,不带有 FLAG_IMMUTABLE 标记创建的 PendingIntent 默认是可变类型的。

    PendingIntent 的使用场景:

    • 通知,在点击通知时执行调起本应用的操作或者其他操作;
    • 闹钟,定时执行某个操作;
    • 桌面小部件,点击小部件时执行某个操作;

    参考

    Android基础——PendingIntent理解
    PendingIntent详解
    PendingIntent
    PendingIntent的解惑
    关于 PendingIntent 您需要知道的那些事

  • 相关阅读:
    如何在Linux部署Portainer并结合内网穿透远程管理本地Docker容器
    Map和Set
    redis变慢原因记录
    Shiro进阶(四)Shiro之RememberMe
    任务4.8.4 利用Spark SQL实现分组排行榜
    9.3 【MySQL】系统表空间
    面试官:RocketMQ 分布式事务消息的缺点?
    【微服务】java 操作elasticsearch详细总结
    Linux 重定向、管道命令 、环境变量PATH、权限理解
    Linux进程概念详解
  • 原文地址:https://blog.csdn.net/xingyu19911016/article/details/127870108