Intent和PendingIntent的区别

116

我阅读了一些文章,所有文章似乎都在做同一件事情,我想知道下面两种方式启动服务的区别:

Intent intent = new Intent(this, HelloService.class);
startService(intent);

或更低:

Calendar cal = Calendar.getInstance();
Intent intent = new Intent(this, MyService.class);
PendingIntent pintent = PendingIntent.getService(this, 0, intent, 0);
AlarmManager alarm = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
alarm.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 30*1000, pintent); 

我阅读了一遍,这两个都是做同样的事情,如果在服务中返回参数START_STICKY;


没有区别。你为什么认为会有区别呢?在第一种情况下,你现在开始它,在第二种情况下,你只是安排它在以后的时间/日期执行。 - Squonk
可能是什么是Android PendingIntent?的重复问题。 - James Moore
6个回答

191

意图

Android中的Intent是一个对象,携带着一条信息从一个组件传递到另一个组件,无论这些组件是应用内还是应用外的。Intent可以在应用程序的三个核心组件——Activity、Service和BroadcastReceiver之间通信。

Intent本身是一个被动的数据结构,它包含着要执行的操作的抽象描述。

例如,假设您有一个需要启动电子邮件客户端并发送电子邮件的Activity。为了实现这一目的,您的Activity将发送一个带有行动 ACTION_SEND的Intent,以及适当的选择器,到Android Intent解析器:

Intent intent = new Intent(Intent.ACTION_SENDTO);
intent.setData(Uri.parse("mailto:")); // only email apps should handle this

指定的chooser为用户选择如何发送电子邮件数据提供了正确的接口。

显式Intent

// Explicit Intent by specifying its class name
   Intent i = new Intent(this, TargetActivity.class);
   i.putExtra("Key1", "ABC");
   i.putExtra("Key2", "123");

// Starts TargetActivity
   startActivity(i);

隐式意图

// Implicit Intent by specifying a URI
   Intent i = new Intent(Intent.ACTION_VIEW, 
   Uri.parse("http://www.example.com"));

// Starts Implicit Activity
   startActivity(i); 

待处理意图

待处理意图是您提供给外部应用程序(例如NotificationManager、AlarmManager、Home Screen AppWidgetManager或其他第三方应用程序)的一种标记,允许外部应用程序使用您的应用程序权限来执行预定义的代码。

通过向另一个应用程序提供待处理意图,您授予其执行您指定操作的权利,就像另一个应用程序是您本身(具有相同的权限和身份)一样。因此,您应该注意如何构建待处理意图:例如,基本Intent应当明确设置为您自己的组件之一,以确保最终发送到那里而不是其他地方。

待处理意图示例:http://android-pending-intent.blogspot.in/

来源: Android IntentsAndroid Pending Intents


33

PendingIntentIntent 的包装器。接收 PendingIntent 的外部应用程序不知道被 PendingIntent 包装的 Intent 内容。外部应用程序的任务是在某些条件满足时(例如:具有时间表的闹钟或带有单击的通知)将意图发送回所有者。条件由所有者提供但由外部应用程序处理(例如:闹钟,通知)。

如果外部应用程序向您的应用程序发送了意图,则说明外部应用程序了解意图的内容。并且外部应用程序决定发送意图,然后您的应用程序必须处理意图以满足某些条件=> 您的应用程序获得系统的性能资源。


12

另一个简单的区别:

  • 普通意图在应用程序关闭后会立即终止。

  • 挂起的意图永远不会消失。只要闹钟服务、位置服务或任何其他服务需要它,它就会一直存在。


6

IntentPendingIntent 之间还有一个主要的区别,需要注意,否则您的应用设计可能会变得易受攻击。该问题在 Android Nesting Intents 文章中有详细描述。

请注意,PendingIntent.send() 方法不接受Context 实例,而是在意图创建时使用提供的上下文。它允许第三方组件在意图创建者的上下文中执行与挂起意图相关联的操作。

假设有一个第三方服务会执行某些任务,然后启动您的应用指定的活动作为意图。如果将回调活动作为基本 Intent 提供,该服务只能使用其自己的上下文来启动它,这种设计具有以下两个缺点:

  • 强制要求将 回调 活动定义为exported,以便可以使用第三方上下文来启动它。结果,该活动不仅可以被其意图指定的服务启动,而且可以被安装在设备上的任何其他应用程序启动。
  • 使用第三方上下文启动,因此可以将第三方服务应用程序定义的任何活动用作 回调 活动,甚至是未导出的活动。

这两个问题都可以通过指定回调活动为PendingIntent轻松解决。


我认为 exported 这个字符是最重要的。 - twlkyao
在我看来,这是最好的答案,而且所提到的文章是无价的。 - HZhang

2

从功能上来说,它们没有区别。

PendingIntent 的含义是您可以将其交给其他应用程序,随后其他应用程序可以像您一样使用它。以下是来自文档的相关解释:

通过向另一个应用程序提供 PendingIntent,您授予其执行您指定操作的权限,就好像该其他应用程序是您本人(具有相同的权限和身份)。因此,您应该小心构建 PendingIntent:

例如,通常情况下,您提供的基本 Intent 应该明确设置为您自己的组件之一的组件名称,以确保最终将其发送到那里而不是其他地方。

PendingIntent 本身只是对由系统维护的令牌的引用,该令牌描述了用于检索它的原始数据。

因此,PendingIntent 只是对表示创建 PendingIntent 的原始 Intent 的数据的引用。


6
说两者在功能上没有区别是不正确的。如果两者的功能相同,为什么一开始要有两者呢?最重要的区别在于PendingIntent由远程组件执行(比如NotificationManager),具有与交接它(创建通知的那个组件)相同的权限。 - Aniket Thakur

1

通过AlarmManager定期启动服务

与活动一样,为了节省资源,Android系统可能随时终止服务进程。因此,您不能仅使用TimerTask在服务中确保其定期执行。

因此,为了正确调度服务,请使用AlarmManager类。

更新:

因此,两者实际上没有区别。 但是,根据您是否想要确保服务的执行,您可以决定使用什么作为前者没有保证而后者有保证。

更多信息请参见AndroidServices


2
这实际上并没有回答楼主的问题,即直接启动服务和使用闹钟启动服务之间的区别是什么。此外,楼主可能已经看过您提供的链接文章,因为该文章中的代码几乎与楼主发布的代码相同。 - Squonk
你是指从AlarmManager启动服务比从Activity更安全,更难被杀死吗?我认为这是错误的。你能解释一下吗?@VedPrakash。此外,我认为在创建用于启动服务的intent时传递的上下文环境更重要。使用应用程序的上下文环境(getApplicationContext())而不是活动的上下文环境(this)应该更安全。 - Parth Kapoor
@Eu.Dr. 我建议您使用闹钟管理器,它将在每个X时间触发任务执行。为什么?因为如果您使用服务,它可能会在某些时候关闭,并且您可能会在某个时间(未知)跳过某些更新。对于上下文的疑问,永远不要使用getApplicationContext()或者只有在需要严格使用时才使用它,只需阅读-when-to-call-activity-context-or-application-context (https://dev59.com/UGw05IYBdhLWcg3wVwc4)。 - My God

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接