PendingIntent详解

看似简单,实在涉及问题太多,有地方目前还是不解,先开篇放这,以后再写


相关文章:

1、《说说PendingIntent的内部机制》  绝对干货

2、《Android开发陷阱:利用PendingIntent传递唯一的Intent》我也碰到相同问题,详见备注

3、《Android-Intent和PendingIntent的关系》

4、《解决PendingIntent传递参数为空的问题》

5、《PendingIntent详解》

6、《PendingIntent详解 》

7、《Android中pendingIntent的深入理解》


备注:

这里有个问题:

以前在写博客时就发现了这个问题,到现在也一直无解,在写这篇文章《桌面widget详解(三)——桌面widget中的控件交互方法》我在博客里使用的是利用Intent.setData()的方式来传递的ID值,但如果用我们传统传递值的方式:intent.putExtra()来传ID值的话,在接收传过来的数值时,总是只有一个

发送时:

这里构造了两个不同的PendingIntent,而且设置了不同的RequestCode,RemoteView绑定如下:

  1. @Override  
  2. public void onUpdate(Context context, AppWidgetManager appWidgetManager,  
  3.         int[] appWidgetIds) {  
  4.   
  5.     // 创建一个Intent对象  
  6.     Intent intent = new Intent();  
  7.     intent.putExtra("id", R.id.btn1);  
  8.     intent.setAction(broadCastString);  
  9.       
  10.     // 设置pendingIntent的作用  
  11.     PendingIntent pendingIntent = PendingIntent.getBroadcast(context,UUID.randomUUID().hashCode(),intent, PendingIntent.FLAG_UPDATE_CURRENT);  
  12.     RemoteViews remoteViews = new RemoteViews(context.getPackageName(),R.layout.example_appwidget);  
  13.     remoteViews.setOnClickPendingIntent(R.id.btn1, pendingIntent);  
  14.       
  15.     // 创建一个Intent对象  
  16.     Intent intent2 = new Intent();  
  17.     intent2.putExtra("id", R.id.btn2);  
  18.     intent2.setAction(broadCastString);  
  19.       
  20.     // 设置pendingIntent的作用  
  21.     PendingIntent pendingIntent2 = PendingIntent.getBroadcast(context, UUID.randomUUID().hashCode(),intent2,PendingIntent.FLAG_UPDATE_CURRENT);  
  22.     RemoteViews remoteViews2 = new RemoteViews(context.getPackageName(),R.layout.example_appwidget);  
  23.     remoteViews2.setOnClickPendingIntent(R.id.btn2, pendingIntent2);  
  24.               
  25.               
  26.     // 更新Appwidget  
  27.     appWidgetManager.updateAppWidget(appWidgetIds, remoteViews);  
  28. }  
接收时,问题来了:

在刚开始,intent.getIntExtra()时,返回的总是R.id.btn1,第二个按钮总是没有任何反应

  1. @Override  
  2. public void onReceive(Context context, Intent intent) {  
  3.       
  4.     if (intent == null) {  
  5.         return;  
  6.     }  
  7.   
  8.     String action = intent.getAction();  
  9.     if (broadCastString.equals(action)) {  
  10.         int id = intent.getIntExtra("id", -1);  
  11.         String str = "";  
  12.         if(id == R.id.btn1){  
  13.             str ="btn 1 click:";  
  14.               
  15.         }else if(id == R.id.btn2){  
  16.             str ="btn 2 click:";  
  17.         }  
  18.         // 只能通过远程对象来设置appwidget中的控件状态  
  19.         RemoteViews remoteViews = new RemoteViews(context.getPackageName(),  
  20.                 R.layout.example_appwidget);  
  21.   
  22.         // 通过远程对象将按钮的文字设置为”一个随机数”  
  23.         Random random1 = new Random();  
  24.         remoteViews.setTextViewText(R.id.text,str + random1.nextInt());  
  25.   
  26.         // 获得appwidget管理实例,用于管理appwidget以便进行更新操作  
  27.         AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);  
  28.   
  29.         // 相当于获得所有本程序创建的appwidget  
  30.         ComponentName componentName = new ComponentName(context,ExampleAppWidgetProvider.class);  
  31.   
  32.         // 更新appwidget  
  33.         appWidgetManager.updateAppWidget(componentName, remoteViews);  
  34.           
  35.         //这里没有绑定pendingIntent,  
  36.     }  
  37.     super.onReceive(context, intent);  
  38. }  


这个东东的源码,在这里:http://download.csdn.net/detail/harvic880925/8278621


参考这篇文章:2、《Android开发陷阱:利用PendingIntent传递唯一的Intent》和PendingIntetn官方文档:http://developer.android.com/reference/android/app/PendingIntent.html

其中有句话:

A PendingIntent itself is simply a reference to a token maintained by the system describing the original data used to retrieve it. This means that, even if its owning application's process is killed, the PendingIntent itself will remain usable from other processes that have been given it. If the creating application later re-retrieves the same kind of PendingIntent (same operation, same Intent action, data, categories, and components, and same flags), it will receive a PendingIntent representing the same token if that is still valid, and can thus call cancel() to remove it.

Because of this behavior, it is important to know when two Intents are considered to be the same for purposes of retrieving a PendingIntent. A common mistake people make is to create multiple PendingIntent objects with Intents that only vary in their "extra" contents, expecting to get a different PendingIntent each time. This does not happen. The parts of the Intent that are used for matching are the same ones defined by Intent.filterEquals. If you use two Intent objects that are equivalent as per Intent.filterEquals, then you will get the same PendingIntent for both of them.

There are two typical ways to deal with this.

If you truly need multiple distinct PendingIntent objects active at the same time (such as to use as two notifications that are both shown at the same time), then you will need to ensure there is something that is different about them to associate them with different PendingIntents. This may be any of the Intent attributes considered by Intent.filterEquals, or different request code integers supplied to getActivity(Context, int, Intent, int)getActivities(Context, int, Intent[], int)getBroadcast(Context, int, Intent, int), or getService(Context, int, Intent, int).

意思就是说,如果要创建两个不同的PendingIntent,而不要系统替换前一个,不要仅仅在PutExtra()中包含不同的内容,因为在Extra的不同,并不会用来识别两个不同的PendingInent,要看两个PendingIntent是否相同,可以利用filterEquals (Intent other)来判断两个Intent是否相同,即除了Extra域的任何不同都会标识为两个不同的Intent.
public boolean filterEquals (Intent other)
Added in  API level 1

Determine if two intents are the same for the purposes of intent resolution (filtering). That is, if their action, data, type, class, and categories are the same. This does not compare any extra data included in the intents.

Parameters
other The other Intent to compare against.
Returns
  • Returns true if action, data, type, class, and categories are the same.
最后一段还说,如果你要构建多个新的PendingIntent而不是让系统替换原有的,要么利用filterEquals (Intent other)里的那几个域的不同来构造不同的Intent,要么在构建PendingIntent时使用不同的RequestCode(这也就是那哥们 《Android开发陷阱:利用PendingIntent传递唯一的Intent》这篇文章所讲的内容)

写到这,发现了上面代码中的一个问题,即我使用了不同的RequestCode,但Intent之间,仅传递数值时仅用了不同的Extra域。

想到这,那我用不同的data域来试一下:

发送:

有没有看出来,下面的代码和《桌面widget详解(三)——桌面widget中的控件交互方法》第三部分:三、进阶——如何响应多个按钮控件,的区别了没,发送方法都是一致的,但这里使用的是匹配Action的匿名发送,而在《桌面widget详解(三)——桌面widget中的控件交互方法》使用的是指定类名的显示发送,但这里是发送不成功的,而显示指定是可以区别的。所以在上一篇博客中是可以成功的,其实在写上篇博客时,我就知道匿名发送是成功不了的,但不知道为什么,怕误解大家,所以就没提。

  1. @Override  
  2. public void onUpdate(Context context, AppWidgetManager appWidgetManager,  
  3.         int[] appWidgetIds) {  
  4.   
  5.     // 创建一个Intent对象  
  6.     Intent intent = new Intent();  
  7.     intent.setData(Uri.parse("harvic:" + R.id.btn1));    
  8.     intent.setAction(broadCastString);  
  9.   
  10.     // 设置pendingIntent的作用  
  11.     PendingIntent pendingIntent = PendingIntent.getBroadcast(context, UUID  
  12.             .randomUUID().hashCode(), intent,  
  13.             PendingIntent.FLAG_UPDATE_CURRENT);  
  14.     RemoteViews remoteViews = new RemoteViews(context.getPackageName(),  
  15.             R.layout.example_appwidget);  
  16.     remoteViews.setOnClickPendingIntent(R.id.btn1, pendingIntent);  
  17.   
  18.     // 创建一个Intent对象  
  19.     Intent intent2 = new Intent();  
  20.     intent2.setData(Uri.parse("harvic:" + R.id.btn2));    
  21.     intent2.setAction(broadCastString);  
  22.   
  23.     // 设置pendingIntent的作用  
  24.     PendingIntent pendingIntent2 = PendingIntent.getBroadcast(context, UUID  
  25.             .randomUUID().hashCode(), intent2,  
  26.             PendingIntent.FLAG_UPDATE_CURRENT);  
  27.     RemoteViews remoteViews2 = new RemoteViews(context.getPackageName(),  
  28.             R.layout.example_appwidget);  
  29.     remoteViews2.setOnClickPendingIntent(R.id.btn2, pendingIntent2);  
  30.   
  31.     // 更新Appwidget  
  32.     appWidgetManager.updateAppWidget(appWidgetIds, remoteViews);  
  33. }  
接收时:

根本接收不到任何东东!!!!!!!

  1. public class ExampleAppWidgetProvider extends AppWidgetProvider {  
  2.     String broadCastString = "harvic.provider";  
  3.   
  4.     @Override  
  5.     public void onReceive(Context context, Intent intent) {  
  6.   
  7.         if (intent == null) {  
  8.             return;  
  9.         }  
  10.   
  11.         String action = intent.getAction();  
  12.         if (broadCastString.equals(action)) {  
  13.             Uri data = intent.getData();    
  14.             int resID = -1;    
  15.             if(data != null){    
  16.                 resID = Integer.parseInt(data.getSchemeSpecificPart());    
  17.             }    
  18.             // 只能通过远程对象来设置appwidget中的控件状态  
  19.             RemoteViews remoteViews = new RemoteViews(context.getPackageName(),  
  20.                     R.layout.example_appwidget);  
  21.   
  22.             // 通过远程对象将按钮的文字设置为”一个随机数”  
  23.             Random random1 = new Random();  
  24.             remoteViews.setTextViewText(R.id.text, resID +":" + random1.nextInt());  
  25.   
  26.             // 获得appwidget管理实例,用于管理appwidget以便进行更新操作  
  27.             AppWidgetManager appWidgetManager = AppWidgetManager  
  28.                     .getInstance(context);  
  29.   
  30.             // 相当于获得所有本程序创建的appwidget  
  31.             ComponentName componentName = new ComponentName(context,  
  32.                     ExampleAppWidgetProvider.class);  
  33.   
  34.             // 更新appwidget  
  35.             appWidgetManager.updateAppWidget(componentName, remoteViews);  
  36.   
  37.             // 这里没有绑定pendingIntent,  
  38.         }  
  39.         super.onReceive(context, intent);  
  40.     }  


改造过的源码在这里:http://download.csdn.net/detail/harvic880925/8278667


洋洋洒洒一大堆,现将问题记录于此,终有一天会海阔天空,相信自己

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值