代码改变世界

PendingIntent分析

2012-10-29 19:19  ...平..淡...  阅读(620)  评论(0编辑  收藏  举报

最近学习中遇到PendingIntent,然后上网找了点资料,总结下了它的用法。

PendingIntent主要用于短信、闹钟、通知栏等模块。

PendingIntent与Intent的区别:

Intent:是及时启动,intent 随所在的activity 消失而消失。 
PendingIntent:可以看作是对Intent的包装。此时,对于该Intent,当前activity不能马上启动它,而是需要在外部程序执行PendingIntent时,才能执行。另外,由于保存了当前App的Context值,使得它能够在当前App销毁时,依然能够执行保存的Intent。

有三个静态方法可以获得PendingIntent实例:

public static PendingIntent getBroadcast(Context context, int requestCode, Intent intent, int flags)  
public static PendingIntent getActivity(Context context, int requestCode, Intent intent, int flags)  
public static PendingIntent getService(Context context, int requestCode, Intent intent, int flags) 
flags参数有以下四种:

FLAG_ONE_SHOT:this PendingIntent can only be used once. If set, after send() is called on it, it will be automatically canceled for you and any future attempt to send through it will fail.

FLAG_UPDATE_CURRENT: 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.
简单解释一下,就是当存在时,先把原来的取消,然后创建一个新的,在AlarmManager服务时,修改一个闹铃,用的比较笨的的方法,先取消,然后重新注册,其实加上这个参数就行了。

要注意的是,这个只更新extra data,不会修改其他内容,不能new一个Intent,还有就是如果你的Intent中需要传递Id或者其他数据,一定要用这个flags或者FLAG_CANCEL_CURRENT,曾经一直接收不到Id,查了半天原来是这个原因 :-(

FLAG_NO_CREATE:if the described PendingIntent does not already exist, then simply return null instead of creating it.

FLAG_CANCEL_CURRENT:if the described PendingIntent already exists, the current one is canceled before generating a new one.You can use this to retrieve a new PendingIntent when you are only changing the extra data in the Intent; by canceling the previous pending intent, this ensures that only entities given the new data will be able to launch it. If this assurance is not an issue, consider FLAG_UPDATE_CURRENT.

 

在短信模块中,SmsManager 类中的sendTextMessage方法中有用PendingIntent:

public final void sendTextMessage (String destinationAddress, String scAddress, String text, PendingIntent sentIntent,PendingIntent deliveryIntent)

 

//第一个参数: destinationAddress  对方手机号码
//第二个参数: scAddress  短信中心号码   一般设置为空
//第三个参数: text  短信内容
//第四个参数: sentIntent:当短信成功发出时,sendIntent会把其内部的描述的intent广播出去,否则产生错误代码并通过android.app.PendingIntent.OnFinished进行回调,这个参数最好不为空,否则会存在资源浪费的潜在问题; 
//第五个参数:deliveryIntent:是当消息已经传递给收信人后所进行的PendingIntent广播。就是说在"短信发送成功"和"对方收到此短信"时才会激活sentIntent和deliveryIntent这两个Intent。这也相当于是延迟执行了Intent

 

在通知栏上的应用,例如下面的代码显示消息,点击后跳转到另一个页面:

private void showNotify(){   
        Notification notice=new Notification();   
        notice.icon=R.drawable.icon;   
        notice.tickerText="您有一条新的信息";   
        notice.defaults=Notification.DEFAULT_SOUND;   
        notice.when=10L; 

        notice.flags = Notification.FLAG_AUTO_CANCEL; //点击后自动取消通知标记
        notice.setLatestEventInfo(this, "通知", "开会啦", PendingIntent.getActivity(this, 0, new Intent(this,Activity2.class), 0));//即将跳转页面,还没跳转   
        NotificationManager manager=(NotificationManager)getSystemService(this.NOTIFICATION_SERVICE);   
        manager.notify(0,notice);   
 }

 

通过闹钟源码,深入分析PendingIntent

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方法。当send操作完成时,会回调这个接口类的onSendFinished方法。
 (PendingIntent.send一般是在service中执行,所以,执行send方法后,回调的onSendFinished一般也是在service中执行的)