PendingIntent 是对真实Intent的一种封装载体,可以用来在出发时,根据Intent 唤起目标组件,如 Activity,Service,BroadcastReceiver 等。
例如,一般的推广行为:接收后台推送消息,并展示在通知栏上,当用户点击消息通知后,唤起指定的目标:
Intent intent = new Intent(action); PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
对于一次性行为,上面的实现没有问题,但对于持续性的操作,问题就来了。
什么是持续性的操作?简单的例子就是,想豆瓣音乐客户端在通知栏上显示的那种,我称它作”远程交互“。
在通栏上的交互,大致的模型是:
作为开发者,我们只需要关注模型中的 Notification 和 BackService 即可。当发生用户交互,通知栏上的通知视图会触发PendingIntent,并将其包含的Intent传到BackService,然后BackService根据具体的逻辑,更新对应的Notification视图,同时绑定新的PendingIntent,对应的代码如下:
PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
为了使得新的PendingIntent生效,我们还特地设置Flag为 PendingIntent.FLAG_UPDATE_CURRENT,ok,现在这一切都没问题。
那我们稍稍把问题在搞复杂一点,我希望PendingIntent中的Intent带上参数,像这样:
Intent intent = new Intent(action); intent.putExtra("data", parcelable);
然后就用PendingIntent封装,然后你再去点击具体的通知-->触发,并在代码中试图取回设置好的 data 时,你会发现取到的data有问题----点击多于二次(或者点击第 2+ 个通知)时,data的值保持不变(和第一个通知,点击第一次取得的值一致)!
Why?
请留意:public static PendingIntent getService ( Context context, int requestCode, Intent intent, int flags)
对比 API Doc 的截图
对于参数 flags 可能的取值有: FLAG_ONE_SHOT, FLAG_NO_CREATE, FLAG_CANCEL_CURRENT, FLAG_UPDATE_CURRENT
一般性而言,我们都会选择 FLAG_UPDATE_CURRENT,直接更新当前存在的PendingIntent,以提高性能。对于FLAG_UPDATE_CURRENT 的意义解析,见下面一段Doc的原文:
上面短文明确指出 keep it but its replace its extra data with what is in this new Intent ,这里就是全文的关键点----PendingIntent的陷阱之在!!!
对于上文中的字面意思,如果判断为新Intent,则会更新对应的extra data,但是系统是如何判定新Intent的?Object.equals?Intent.filterEquals!但是从源码分析,filrerEquals 比较拥有同样的Action,不一样的data的 Intent 必定是返回false的,那问题还会出在哪呢?
不好意思,我们还漏了一个参数:requestCode,但是doc上明写着:currently not used。类比Activity.startActivityForResult(Content content, Class<?> cls, int resquestCode)得知,resquestCode也是请求的唯一标志!
之后尝试一下的逻辑代码:
Intent intent = new Intent(action); intent.putExtra("data", parcelable); PendingIntent pendingIntent = PendingIntent.getService(context, UUID.randomUUID().hashCode(), intent, PendingIntent.FLAG_UPDATE_CURRENT);
结果不言而喻......
其实从getService的源码实现可以看出一点端倪:
public static PendingIntent getService(Context context, int requestCode, Intent intent, int flags) { String packageName = context.getPackageName(); String resolvedType = intent != null ? intent.resolveTypeIfNeeded( context.getContentResolver()) : null; try { intent.setAllowFds(false); IIntentSender target = ActivityManagerNative.getDefault().getIntentSender( ActivityManager.INTENT_SENDER_SERVICE, packageName, null, null, requestCode, new Intent[] { intent }, resolvedType != null ? new String[] { resolvedType } : null, flags, null, UserHandle.myUserId()); return target != null ? new PendingIntent(target) : null; } catch (RemoteException e) { } return null; }PendingIntent其实也是对 IItentSender 的一个封装,那就意味着,在更新 PendingIntent 时,系统比较的应该是 IIntentSender,从那一大串“构造参数”来看,requestCode也在其中,这关系就脱不了了。
最后,总结一句,Google 你这不是明摆着坑人吗?请看最新的最先Doc(ps:本地的SDK版本是 4.2.2):
参考资料:
- http://stackoverflow.com/questions/4340431/how-can-i-correctly-pass-unique-extras-to-a-pending-intent
- http://stackoverflow.com/questions/4689029/send-extra-data-via-pendingintent-problem
- http://stackoverflow.com/questions/10537006/intent-extras-are-duplicated-when-using-flag-update-current-in-pendingintent-whe
相关推荐
在Android开发中,PendingIntent是一个非常重要的组件,它允许我们延迟执行某个操作或者将操作传递给其他应用。这个组件在很多场景下都有广泛的应用,比如通知、BroadcastReceiver、Service等。接下来,我们将深入...
在Android开发环境中,Intent是应用间通信的重要工具,它用于启动其他组件或传递数据。本实验将深入探讨Android Studio中Intent的使用,帮助你更好地理解如何在不同的Activity之间跳转和传递信息。 首先,让我们...
在Android开发中,Intent和PendingIntent是两个非常重要的概念,它们在组件间的通信中起到关键作用。Intent可以理解为一种消息传递对象,用于在不同组件之间传递行为和数据,而PendingIntent则是Intent的一种封装,...
在Android开发中,PendingIntent是一个非常关键且独特的组件,它为应用程序提供了跨进程通信的能力,使得一个应用可以请求系统在未来的某个时刻执行特定的操作。PendingIntent不仅涉及到了Android的权限模型,还涉及...
在Android开发中,`PendingIntent`是一个非常关键的组件,它允许一个应用组件(如Activity、Service或BroadcastReceiver)在另一个应用组件中执行一个动作,即使原来的组件已经被销毁或者当前进程不可用。...
**Android支持库:Android Support V4** Android Support Library V4,简称`android-support-v4`,是Android开发者广泛使用的库,旨在提供对Android早期版本的兼容性,同时包含许多先进的特性,使得应用能够运行在...
综上所述,PendingIntent是Android开发中的一个重要工具,它允许开发者在不同组件之间安全地传递和延迟执行Intent操作,为应用的复杂交互提供了便利。理解并正确使用PendingIntent对于编写健壮、安全的Android应用至...
在Android开发中,Intent和PendingIntent是两个非常关键的概念,它们在应用程序的组件间通信中起着重要作用。Intent主要用于启动或传递数据给另一个组件,如Activity、Service或BroadcastReceiver,而PendingIntent...
例如,你可以创建一个Intent,指定要启动的Activity,然后将这个Intent传递给PendingIntent的getActivity()或getService()方法。这样,当用户点击通知时,系统会使用这个PendingIntent来启动指定的组件。在描述的...
在Android应用开发中,服务(Service)是一种在后台运行的组件,它不具有用户界面,但可以执行长时间的任务,如播放音乐、网络通信等。Service生命周期中的关键方法包括`onStartCommand()`和`onBind()`,前者用于...
在Android应用开发中,Intent是一种强大的机制,用于在组件之间传递数据和启动操作。Intent不仅可以用来启动活动(Activity)、服务(Service),还可以用于广播接收器(Broadcast Receiver)之间的通信。本教程将...
13. **PendingIntent**:PendingIntent是Intent的封装,允许将Intent传递给第三方应用或系统服务,比如设置闹钟或发送通知。 14. **Intent chooser**:通过`createChooser(Intent, String)`方法,可以展示一个让...
在Android开发中,Intent是一个非常核心且至关重要的组件,它扮演着应用程序内部或不同应用程序之间通信的桥梁。Intent1_Intent.zip中的源码应该包含了关于Intent的实例和使用方法,让我们一起深入探讨Intent在...
总之,Intent在Android开发中无处不在,从启动Activity到启动Service,从数据传递到组件间的通信,都离不开Intent的使用。理解并熟练掌握Intent的使用,对于编写高效、健壮的Android应用程序至关重要。通过阅读提供...
PendingIntent是Android系统中一个非常重要的概念,它是Intent的一个特殊形式,主要用于在应用程序的组件之间传递意图(Intent),并确保这些意图在特定的时间或由特定的事件触发时得到执行。与普通的Intent不同,...
在Android开发中,`PendingIntent`是一个至关重要的组件,它允许其他应用或系统服务代表我们的应用执行操作。这篇博客的第二部分深入剖析了`PendingIntent`的源码,揭示了其工作原理和潜在问题。`PendingIntent`的...
在Android开发中,Intent是一种非常重要的组件,它用于在应用程序的不同组件之间传递消息,实现活动(Activity)、服务(Service)、广播接收器(BroadcastReceiver)以及内容提供者(ContentProvider)之间的交互。...
在Android开发中,Intent是一个非常核心且至关重要的概念。Intent主要负责在应用程序的不同组件之间进行通信,例如在Activity之间、Activity与Service之间,甚至可以触发BroadcastReceiver。在本"安卓基本知识之...
简单的总结了Intent和PendtingIntent的区别,经常与alermanger 和notificationmanager一起使用。