`
zhiweiofli
  • 浏览: 515041 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

Android开发陷阱:利用PendingIntent传递唯一的Intent

阅读更多

 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的原文:

写道
Flag for use with getActivity(Context, int, Intent, int), getBroadcast(Context, int, Intent, int), and getService(Context, int, Intent, int): if the described PendingIntent already exists, then keep it but its replace its extra data with what is in this new Intent. This can be used if you are creating intents where only the extras change, and don't care that any entities that received your previous PendingIntent will be able to launch it with your new extras even if they are not explicitly given to it.

上面短文明确指出  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):



参考资料:

 

 

 

 

1
0
分享到:
评论

相关推荐

    Android 之 PendingIntent用法介绍

    在Android开发中,PendingIntent是一个非常重要的组件,它允许我们延迟执行某个操作或者将操作传递给其他应用。这个组件在很多场景下都有广泛的应用,比如通知、BroadcastReceiver、Service等。接下来,我们将深入...

    Android Studio 实验二:Intent的使用

    在Android开发环境中,Intent是应用间通信的重要工具,它用于启动其他组件或传递数据。本实验将深入探讨Android Studio中Intent的使用,帮助你更好地理解如何在不同的Activity之间跳转和传递信息。 首先,让我们...

    安卓之 (解决问题)PendingIntent和Intent的区别1

    在Android开发中,Intent和PendingIntent是两个非常重要的概念,它们在组件间的通信中起到关键作用。Intent可以理解为一种消息传递对象,用于在不同组件之间传递行为和数据,而PendingIntent则是Intent的一种封装,...

    Android中pendingIntent的深入理解

    在Android开发中,PendingIntent是一个非常关键且独特的组件,它为应用程序提供了跨进程通信的能力,使得一个应用可以请求系统在未来的某个时刻执行特定的操作。PendingIntent不仅涉及到了Android的权限模型,还涉及...

    博客《详解PendingIntent》对应的有问题的PendingIntent源码

    在Android开发中,`PendingIntent`是一个非常关键的组件,它允许一个应用组件(如Activity、Service或BroadcastReceiver)在另一个应用组件中执行一个动作,即使原来的组件已经被销毁或者当前进程不可用。...

    android支持包:android-support-v4

    **Android支持库:Android Support V4** Android Support Library V4,简称`android-support-v4`,是Android开发者广泛使用的库,旨在提供对Android早期版本的兼容性,同时包含许多先进的特性,使得应用能够运行在...

    PendingIntent

    综上所述,PendingIntent是Android开发中的一个重要工具,它允许开发者在不同组件之间安全地传递和延迟执行Intent操作,为应用的复杂交互提供了便利。理解并正确使用PendingIntent对于编写健壮、安全的Android应用至...

    Android中pendingIntent与Intent的深入分析

    在Android开发中,Intent和PendingIntent是两个非常关键的概念,它们在应用程序的组件间通信中起着重要作用。Intent主要用于启动或传递数据给另一个组件,如Activity、Service或BroadcastReceiver,而PendingIntent...

    PendingIntent 使用示例

    例如,你可以创建一个Intent,指定要启动的Activity,然后将这个Intent传递给PendingIntent的getActivity()或getService()方法。这样,当用户点击通知时,系统会使用这个PendingIntent来启动指定的组件。在描述的...

    android 服务 Service PendingIntent 通知

    在Android应用开发中,服务(Service)是一种在后台运行的组件,它不具有用户界面,但可以执行长时间的任务,如播放音乐、网络通信等。Service生命周期中的关键方法包括`onStartCommand()`和`onBind()`,前者用于...

    数据传递之Intent

    在Android应用开发中,Intent是一种强大的机制,用于在组件之间传递数据和启动操作。Intent不仅可以用来启动活动(Activity)、服务(Service),还可以用于广播接收器(Broadcast Receiver)之间的通信。本教程将...

    android开发范例大全第八章-与Intent接轨

    13. **PendingIntent**:PendingIntent是Intent的封装,允许将Intent传递给第三方应用或系统服务,比如设置闹钟或发送通知。 14. **Intent chooser**:通过`createChooser(Intent, String)`方法,可以展示一个让...

    Android应用源码之Intent1_Intent.zip

    在Android开发中,Intent是一个非常核心且至关重要的组件,它扮演着应用程序内部或不同应用程序之间通信的桥梁。Intent1_Intent.zip中的源码应该包含了关于Intent的实例和使用方法,让我们一起深入探讨Intent在...

    Andriod Intent使用代码举例

    总之,Intent在Android开发中无处不在,从启动Activity到启动Service,从数据传递到组件间的通信,都离不开Intent的使用。理解并熟练掌握Intent的使用,对于编写高效、健壮的Android应用程序至关重要。通过阅读提供...

    Android中PendingIntent的简要介绍.pdf

    PendingIntent是Android系统中一个非常重要的概念,它是Intent的一个特殊形式,主要用于在应用程序的组件之间传递意图(Intent),并确保这些意图在特定的时间或由特定的事件触发时得到执行。与普通的Intent不同,...

    博客《详解PendingIntent》有问题的源码第二部分

    在Android开发中,`PendingIntent`是一个至关重要的组件,它允许其他应用或系统服务代表我们的应用执行操作。这篇博客的第二部分深入剖析了`PendingIntent`的源码,揭示了其工作原理和潜在问题。`PendingIntent`的...

    Android代码-Intent切换.zip

    在Android开发中,Intent是一种非常重要的组件,它用于在应用程序的不同组件之间传递消息,实现活动(Activity)、服务(Service)、广播接收器(BroadcastReceiver)以及内容提供者(ContentProvider)之间的交互。...

    安卓基本知识之Intent学习源代码

    在Android开发中,Intent是一个非常核心且至关重要的概念。Intent主要负责在应用程序的不同组件之间进行通信,例如在Activity之间、Activity与Service之间,甚至可以触发BroadcastReceiver。在本"安卓基本知识之...

    Intent和PendingIntent的区别

    简单的总结了Intent和PendtingIntent的区别,经常与alermanger 和notificationmanager一起使用。

Global site tag (gtag.js) - Google Analytics