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());
    }
}

对于参数 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;
    }
}

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

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

PendingIntent 的使用场景:

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

参考

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值