1、基本概念
intent英文意思是意图,pending表示即将发生或来临的事情。
PendingIntent这个类用于处理即将发生的事情。比如在通知Notification中用于跳转页面,但不是马上跳转。
Intent 是及时启动,intent 随所在的activity 消失而消失。
PendingIntent 可以看作是对intent的包装,通常通过getActivity,getBroadcast ,getService来得到pendingintent的实例,当前activity并不能马上启动它所包含的intent,而是在外部执行 pendingintent时,调用intent的。正由于pendingintent中 保存有当前App的Context,使它赋予外部App一种能力,使得外部App可以如同当前App一样的执行pendingintent里的 Intent, 就算在执行时当前App已经不存在了,也能通过存在pendingintent里的Context照样执行Intent。另外还可以处理intent执行后的操作。常和alermanger 和notificationmanager一起使用。
Intent一般是用作Activity、Sercvice、BroadcastReceiver之间传递数据,而Pendingintent,一般用在 Notification上,可以理解为延迟执行的intent,PendingIntent是对Intent一个包装。
2、例子
2.1 通知的例子
private void showNotify(){
Notification notice=new Notification();
notice.icon=R.drawable.icon;
notice.tickerText="您有一条新的信息";
notice.defaults=Notification.DEFAULT_SOUND;
notice.when=10L;
// 100 毫秒延迟后,震动 250 毫秒,暂停 100 毫秒后,再震动 500 毫秒
//notice.vibrate = new long[] { 100, 250, 100, 500 };出错?
//notice.setLatestEventInfo(this, "通知", "开会啦", PendingIntent.getActivity(this, 0, null, 0));
notice.setLatestEventInfo(this, "通知", "开会啦", PendingIntent.getActivity(this, 0, new Intent(this,Activity2.class), 0));//即将跳转页面,还没跳转
NotificationManager manager=(NotificationManager)getSystemService(this.NOTIFICATION_SERVICE);
manager.notify(0,notice);
}
2.1 短信发送的例子
String msg ="你好,美女";
String number = "135****6784";
SmsManager sms = SmsManager.getDefault();
PendingIntent pi = PendingIntent.getBroadcast(SmsActivity.this,0,new Intent(...),0);
sms.sendTextMessage(number, null, msg, pi, null);
Toast.makeText(SmsActivity.this,"发送成功",Toast.LENGHT_LONG).show();
PendingIntent就是一个Intent的描述,我们可以把这个描述交给别的程序,别的程序根据这个描述在后面的别的时间做你安排做的事情 (By giving a PendingIntent to another application, you are granting it the right to perform the operation you have specified as if the other application was yourself,就相当于PendingIntent代表了Intent)。本例中别的程序就是发送短信的程序,短信发送成功后要把intent广播出去 。
函数SmsManager.sendTextMessage(String destinationAddress, String scAddress, String text, PendingIntent sentIntent, PendingIntent deliveryIntent)中参数解释:
1)PendingIntent sentIntent:当短信发出时,成功的话sendIntent会把其内部的描述的intent广播出去,否则产生错误代码并通过android.app.PendingIntent.OnFinished进行回调,这个参数最好不为空,否则会存在资源浪费的潜在问题;
2)PendingIntent deliveryIntent:是当消息已经传递给收信人后所进行的PendingIntent广播。
查看PendingIntent 类可以看到许多的Send函数,就是PendingIntent在进行被赋予的相关的操作。
3、PendingIntent的执行过程
以alarm service为例:
1. activity请求一个alarm一般这样来做:
# //创建一个PendingIntent
# Intent intent = new Intent(ALARM_ALERT_ACTION);
# intent.putExtra(ID, id);
# intent.putExtra(TIME, atTimeInMillis);
# PendingIntent sender = PendingIntent.getBroadcast(
# context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
# //获得AlarmMnager并注册一个新闹铃,
# //一次性闹铃的设置
#
# AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);
# am.set(AlarmManager.POWER_OFF_WAKEUP, atTimeInMillis, sender);
2. AlarmManager.set调用AlarmManagerService.set
3. AlarmManagerService.set的核心代码如下:
我们可以看到它就是把PendingIntent保存起来而已
4. alarm manager service会定时查看是否有alarm到期了,如果到期了做相应处理。
5. AlarmThread会调用
alarm.operation.send(mContext, 0,
mBackgroundIntent.putExtra(
Intent.EXTRA_ALARM_COUNT, alarm.count),
mResultReceiver, mHandler);
也就是通过PendingIntent.send执行intent操作,alarm这个就会发送ALARM_ALERT_ACTION的broadcast。
补充说明:
1. PendingIntent重要特点是异步处理。
2. 另外有一个要说明的是PendingIntent.onFinished,它可以作为PendingIntent.send的一个参数,
我们知道PendingIntent.send一般是在service中执行,这个调用的send后,回调onFished类的onSendFinished,所以onSendFinished一般也是在service中执行的
4、深入分析
public final class PendingIntent extends Object implements Parcelable
PendingIntent用于描述Intent及其最终的行为.
- 你可以通过getActivity(Context context, int requestCode, Intent intent, int flags)系列方法从系统取得一个用于启动一个Activity的PendingIntent对象,
- 可以通过getService(Context context, int requestCode, Intent intent, int flags)方法从系统取得一个用于启动一个Service的PendingIntent对象
- 可以通过getBroadcast(Context context, int requestCode, Intent intent, int flags)方法从系统取得一个用于向BroadcastReceiver的Intent广播的PendingIntent对象
当你把PendingIntent递交给别的程序进行处理时,PendingIntent仍然拥有PendingIntent原程序所拥有的权限(with the same permissions and identity).当你从系统取得一个PendingIntent时,一定要非常小心才行。比如,通常,如果Intent目的地是你自己的component(Activity/Service/BroadcastReceiver)的话,你最好采用在Intent中显示指定目的component名字的方式,以确保Intent最终能发到目的,否则Intent最后可能不知道发到哪里了。一个PendingIntent就是Android系统中的一个token(节点,这个应该是Linux或C\C++用语)的一个对象引用,它描述了一些将用于retrieve的数据(这里,这些数据描述了Intent及其最终的行为)。
这就意味着即使PendingIntent原进程结束了的话, PendingIntent本身仍然还存在,可在其他进程(PendingIntent被递交到的其他程序)中继续使用.如果我在从系统中提取一个PendingIntent的,而系统中有一个和你描述的PendingIntent对等的PendingInent, 那么系统会直接返回和该PendingIntent其实是同一token的PendingIntent,而不是一个新的token和PendingIntent。然而你在从提取PendingIntent时,通过FLAG_CANCEL_CURRENT参数,让这个老PendingIntent的先cancel()掉,这样得到的pendingInten和其token的就是新的了。
通过FLAG_UPDATE_CURRENT参数的话,可以让新的Intent会更新之前PendingIntent中的Intent对象数据,例如更新Intent中的Extras。另外,我们也可以在PendingIntent的原进程中调用PendingIntent的cancel ()把其从系统中移除掉。
注意:两个PendingIntent对等是指它们的operation一样, 且其它们的Intent的action, data, categories, components和flags都一样。但是它们的Intent的Extra可以不一样。
4.1 主要常量
- FLAG_CANCEL_CURRENT:如果当前系统中已经存在一个相同的PendingIntent对象,那么就将先将已有的PendingIntent取消,然后重新生成一个PendingIntent对象。
- FLAG_NO_CREATE:如果当前系统中不存在相同的PendingIntent对象,系统将不会创建该PendingIntent对象而是直接返回null。
- FLAG_ONE_SHOT:该PendingIntent只作用一次。在该PendingIntent对象通过send()方法触发过后,PendingIntent将自动调用cancel()进行销毁,那么如果你再调用send()方法的话,系统将会返回一个SendIntentException。
- FLAG_UPDATE_CURRENT:如果系统中有一个和你描述的PendingIntent对等的PendingInent,那么系统将使用该PendingIntent对象,但是会使用新的Intent来更新之前PendingIntent中的Intent对象数据,例如更新Intent中的Extras。
- getActivities系列方法
public static PendingIntent getActivity (Context context, int requestCode, Intent intent, int flags)
Since: API Level 1
Retrieve a PendingIntent that will start a new activity, like calling Context.startActivity(Intent). Note that the activity will be started outside of the context of an existing activity, so you must use the Intent.FLAG_ACTIVITY_NEW_TASK launch flag in the Intent.
因为对于Context的startActivity方法,如果不是在其子类(Activity)中调用,那么必须对Intent加上FLAG_ACTIVITY_NEW_TASK。
具体可以参照Context中对startActivity方法的说明或《Activity和Task的基本模型》
Parameters
context The Context in which this PendingIntent should start the activity.
requestCode Private request code for the sender (currently not used).
intent Intent of the activity to be launched.
flags May be FLAG_ONE_SHOT, FLAG_NO_CREATE, FLAG_CANCEL_CURRENT, FLAG_UPDATE_CURRENT, or any of the flags as supported byIntent.fillIn() to control which unspecified parts of the intent that can be supplied when the actual send happens.
当我们使用Intent.fillIn()方法时,表示其Intent的某个数据项可以被send方法的Inent参数进行覆盖重写。
Returns
Returns an existing or new PendingIntent matching the given parameters. May return null only if FLAG_NO_CREATE has been supplied.
public static PendingIntent getActivities (Context context, int requestCode, Intent[] intents, int flags)
Since: API Level 11
Like getActivity(Context, int, Intent, int), but allows an array of Intents to be supplied. The first Intent in the array is taken as the primary key for the PendingIntent, like the single Intent given to getActivity(Context, int, Intent, int). Upon sending the resulting PendingIntent, all of the Intents are started in the same way as they would be by passing them to startActivities(Intent[]).
The first intent in the array will be started outside of the context of an existing activity, so you must use the Intent.FLAG_ACTIVITY_NEW_TASK launch flag in the Intent. (Activities after the first in the array are started in the context of the previous activity in the array, so FLAG_ACTIVITY_NEW_TASK is not needed nor desired for them.)
The last intent in the array represents the key for the PendingIntent. In other words, it is the significant element for matching (as done with the single intent given togetActivity(Context, int, Intent, int), its content will be the subject of replacement by send(Context, int, Intent) andFLAG_UPDATE_CURRENT, etc. This is because it is the most specific of the supplied intents, and the UI the user actually sees when the intents are started.
Parameters
context The Context in which this PendingIntent should start the activity.
requestCode Private request code for the sender (currently not used).
intents Array of Intents of the activities to be launched.
flags May be FLAG_ONE_SHOT, FLAG_NO_CREATE, FLAG_CANCEL_CURRENT, FLAG_UPDATE_CURRENT, or any of the flags as supported byIntent.fillIn() to control which unspecified parts of the intent that can be supplied when the actual send happens.
当我们使用Inent.fillIn()所支持的flags时,表示其Intent的数据项可以被send方法的Intent参数覆盖重写。
Returns
Returns an existing or new PendingIntent matching the given parameters. May return null only if FLAG_NO_CREATE has been supplied.
- getService方法
public static PendingIntent getService (Context context, int requestCode, Intent intent, int flags)
Since: API Level 1
Retrieve a PendingIntent that will start a service, like calling Context.startService(). The start arguments given to the service will come from the extras of the Intent.
Parameters
context The Context in which this PendingIntent should start the service.
requestCode Private request code for the sender (currently not used).
intent An Intent describing the service to be started.
flags May be FLAG_ONE_SHOT, FLAG_NO_CREATE, FLAG_CANCEL_CURRENT, FLAG_UPDATE_CURRENT, or any of the flags as supported byIntent.fillIn() to control which unspecified parts of the intent that can be supplied when the actual send happens.
当我们使用Intent.fillIn()方法的flags时,它表示其Intent的数据项可以被send方法的Intent参数覆盖重写。
Returns
Returns an existing or new PendingIntent matching the given parameters. May return null only if FLAG_NO_CREATE has been supplied.
- getBroadcast方法
public static PendingIntent getBroadcast (Context context, int requestCode, Intent intent, int flags)
Since: API Level 1
Retrieve a PendingIntent that will perform a broadcast, like calling Context.sendBroadcast().
Parameters
context The Context in which this PendingIntent should perform the broadcast.
requestCode Private request code for the sender (currently not used).
intent The Intent to be broadcast.
flags May be FLAG_ONE_SHOT, FLAG_NO_CREATE, FLAG_CANCEL_CURRENT, FLAG_UPDATE_CURRENT, or any of the flags as supported byIntent.fillIn() to control which unspecified parts of the intent that can be supplied when the actual send happens.
当我们使用Intent.fillIn()方法的flags时,它表示其Intent的数据项可以被send方法的Intent参数覆盖重写。
Returns
Returns an existing or new PendingIntent matching the given parameters. May return null only if FLAG_NO_CREATE has been supplied.
- send系列方法
public void send ()
Since: API Level 1
Perform the operation associated with this PendingIntent.
Throws
PendingIntent.CanceledException Throws CanceledException if the PendingIntent is no longer allowing more intents to be sent through it.
public void send (Context context, int code, Intent intent)
Since: API Level 1
Perform the operation associated with this PendingIntent, allowing the caller to specify information about the Intent to use.
Parameters
context The Context of the caller.
该参数是因为intent参数才需要提供的,所用如果你的intent参数不为null的话,该参数也不能为null.
code Result code to supply back to the PendingIntent's target.
intent Additional Intent data. See Intent.fillIn() for information on how this is applied to the original Intent.
Throws
PendingIntent.CanceledException Throws CanceledException if the PendingIntent is no longer allowing more intents to be sent through it.
public void send (int code, PendingIntent.OnFinished onFinished, Handler handler)
Since: API Level 1
Perform the operation associated with this PendingIntent, allowing the caller to be notified when the send has completed.
Parameters
code Result code to supply back to the PendingIntent's target.
onFinished The object to call back on when the send has completed, or null for no callback.
通过该参数,我们可以设置在Intent发送成功后的回调函数。
handler Handler identifying the thread on which the callback should happen. If null, the callback will happen from the thread pool of the process.
用于说明onFinished参数指定的回调函数,最终在哪个Handler中进行调用。
Throws
PendingIntent.CanceledException Throws CanceledException if the PendingIntent is no longer allowing more intents to be sent through it.
public void send (Context context, int code, Intent intent, PendingIntent.OnFinished onFinished, Handler handler)
Since: API Level 1
Perform the operation associated with this PendingIntent, allowing the caller to specify information about the Intent to use and be notified when the send has completed.
For the intent parameter, a PendingIntent often has restrictions on which fields can be supplied here, based on how the PendingIntent was retrieved ingetActivity(Context, int, Intent, int), getBroadcast(Context, int, Intent, int), or getService(Context, int, Intent, int).
Parameters
context The Context of the caller. This may be null if intent is also null.
该参数是因为intent参数才需要提供的,一般是当前的context,如果你的intent参数不为null的话,该函数也不能为null.
code Result code to supply back to the PendingIntent's target.
intent Additional Intent data. See Intent.fillIn() for information on how this is applied to the original Intent. Use null to not modify the original Intent.
onFinished The object to call back on when the send has completed, or null for no callback.
通过该参数,我们可以指定Intent发送成功后的回调函数。
handler Handler identifying the thread on which the callback should happen. If null, the callback will happen from the thread pool of the process.
该参数说明onFinished参数指定的回调函数将在哪个Handler中进行调用。
Throws
PendingIntent.CanceledException Throws CanceledException if the PendingIntent is no longer allowing more intents to be sent through it.
- cancel()函数
public void cancel ()
Since: API Level 1
Cancel a currently active PendingIntent. Only the original application owning an PendingIntent can cancel it.
只有PengdingIntent的原应用程序才能调用cancel()来把它从系统中移除掉。
getTargetPackage()函数
public String getTargetPackage ()
Since: API Level 1
Return the package name of the application that created this PendingIntent, that is the identity under which you will actually be sending the Intent. The returned string is supplied by the system, so that an application can not spoof its package.
Returns
The package name of the PendingIntent, or null if there is none associated with it.
参考资料: