1. 连续发送两条信息时,出现bug。以下是bug现象描述。

发送第一条信息,sentReceiver弹出toast告知发送成功,同时在listview中的发送状态立即同步更新为发送成功。

继续发送第二条信息,sentReceiver也弹出toast告知发送成功,但是在listView中发送状态仍然是正在发送中。

在QQ通讯录中查看第二条信息,发现它的发送状态也是正在发送中,QQ通讯录已经将状态改为发送失败了。

再次试验,连续发送两条信息之后,第二条发送成功之后,它的发送状态没有改变为发送成功,而是仍然保留正在发送中。

2. 确定产生bug的代码。

private void createAndRegisterSentReceiver() {
    sentReceiver = new BroadcastReceiver(){
        @Override
        public void onReceive(Context context, Intent intent) {
            Uri uri = intent.getParcelableExtra(TxrjConstant.EXTRA_SENT_URI);
            int resultCode = getResultCode();
            if(resultCode == RESULT_OK) {
                Toast.makeText(context, "send message success.", Toast.LENGTH_SHORT).show();
                updateMsgType(uri, Sms.MESSAGE_TYPE_SENT); // 难道是这条语句没有执行
            } else if(resultCode == SmsManager.RESULT_ERROR_GENERIC_FAILURE) {
                Toast.makeText(context, "Generic failure.", Toast.LENGTH_SHORT).show();
                updateMsgType(uri, Sms.MESSAGE_TYPE_FAILED);
            } else if(resultCode == SmsManager.RESULT_ERROR_NO_SERVICE) {
                Toast.makeText(context, "service is currently unavailable.", Toast.LENGTH_SHORT).show();
                updateMsgType(uri, Sms.MESSAGE_TYPE_FAILED);
            } else if(resultCode == SmsManager.RESULT_ERROR_NULL_PDU) {
                Toast.makeText(context, "no pdu provided.", Toast.LENGTH_SHORT).show();
                updateMsgType(uri, Sms.MESSAGE_TYPE_FAILED);
            } else if(resultCode == SmsManager.RESULT_ERROR_RADIO_OFF) {
                Toast.makeText(context, "radio was explicitly turned off.", Toast.LENGTH_SHORT).show();
                updateMsgType(uri, Sms.MESSAGE_TYPE_FAILED);
            }
        }
    };
    IntentFilter filter = new IntentFilter(TxrjConstant.ACTION_SEND_SMS);
    mContext.registerReceiver(sentReceiver, filter);
}

private void updateMsgType(Uri uri, int type) {
    ContentValues values = new ContentValues();
    values.put(Sms.TYPE, type);
    getContentResolver().update(uri, values, null, null);
}

private PendingIntent getSentIntent(final Uri uri) {
    if(sentReceiver == null) {
        createAndRegisterSentReceiver();
    }
    Intent sentIntent = new Intent(TxrjConstant.ACTION_SEND_SMS);
    sentIntent.putExtra(TxrjConstant.EXTRA_SENT_URI, uri);
    return PendingIntent.getBroadcast(mContext, 0, sentIntent, 0);
}

3. 跟踪看看每次Uri是不是相同。

先后发出两条信息的URI在在performSendMessage方法中表现为不同,但在onReceive方法中表现为相同。

07-16 12:34:09.879: I/txrjsms(3333): performSendMessage. Uri:content://sms/4003
07-16 12:34:12.421: I/txrjsms(3333): sentReceiver. Uri:content://sms/4003
07-16 12:34:27.646: I/txrjsms(3333): performSendMessage. Uri:content://sms/4005
07-16 12:34:30.229: I/txrjsms(3333): sentReceiver. Uri:content://sms/4003

4. 将getSentIntent(final Uri uri)中的final修饰符去掉,继续测验。

07-16 12:35:58.885: I/txrjsms(3592): performSendMessage. Uri:content://sms/4007
07-16 12:36:01.278: I/txrjsms(3592): sentReceiver. Uri:content://sms/4007
07-16 12:36:21.347: I/txrjsms(3592): performSendMessage. Uri:content://sms/4009
07-16 12:36:24.090: I/txrjsms(3592): sentReceiver. Uri:content://sms/4007

5. 在中间过程多加几个LOG。

07-16 12:39:36.648: I/txrjsms(3886): performSendMessage. Uri:content://sms/4011
07-16 12:39:36.658: I/txrjsms(3886): sendMessage. Uri:content://sms/4011
07-16 12:39:36.888: I/txrjsms(3886): getSentIntent. Uri:content://sms/4011
07-16 12:39:39.290: I/txrjsms(3886): sentReceiver. Uri:content://sms/4011
07-16 12:39:55.766: I/txrjsms(3886): performSendMessage. Uri:content://sms/4013
07-16 12:39:55.776: I/txrjsms(3886): sendMessage. Uri:content://sms/4013
07-16 12:39:55.786: I/txrjsms(3886): getSentIntent. Uri:content://sms/4013
07-16 12:39:58.199: I/txrjsms(3886): sentReceiver. Uri:content://sms/4011

由此可以初步判断出BUG的原因是以下语句在传递Uri数据时出现了问题。

    Intent sentIntent = new Intent(TxrjConstant.ACTION_SEND_SMS);
    sentIntent.putExtra(TxrjConstant.EXTRA_SENT_URI, uri);
    return PendingIntent.getBroadcast(mContext, 0, sentIntent, 0);

6. 改成如下代码也无法解决问题。

private void createSentReceiver() {
    sentReceiver = new BroadcastReceiver(){
        @Override
        public void onReceive(Context context, Intent intent) {
            Uri uri = intent.getParcelableExtra(TxrjConstant.EXTRA_SENT_URI);
            Log.i("txrjsms", "sentReceiver. Uri:"+uri);
            int resultCode = getResultCode();
            if(resultCode == RESULT_OK) {
                Toast.makeText(context, "send message success.", Toast.LENGTH_SHORT).show();
                updateMsgType(uri, Sms.MESSAGE_TYPE_SENT);
            } else if(resultCode == SmsManager.RESULT_ERROR_GENERIC_FAILURE) {
                Toast.makeText(context, "Generic failure.", Toast.LENGTH_SHORT).show();
                updateMsgType(uri, Sms.MESSAGE_TYPE_FAILED);
            } else if(resultCode == SmsManager.RESULT_ERROR_NO_SERVICE) {
                Toast.makeText(context, "service is currently unavailable.", Toast.LENGTH_SHORT).show();
                updateMsgType(uri, Sms.MESSAGE_TYPE_FAILED);
            } else if(resultCode == SmsManager.RESULT_ERROR_NULL_PDU) {
                Toast.makeText(context, "no pdu provided.", Toast.LENGTH_SHORT).show();
                updateMsgType(uri, Sms.MESSAGE_TYPE_FAILED);
            } else if(resultCode == SmsManager.RESULT_ERROR_RADIO_OFF) {
                Toast.makeText(context, "radio was explicitly turned off.", Toast.LENGTH_SHORT).show();
                updateMsgType(uri, Sms.MESSAGE_TYPE_FAILED);
            }
            mContext.unregisterReceiver(sentReceiver);
            sentReceiver = null;
        }
    };
}

private void updateMsgType(Uri uri, int type) {
    ContentValues values = new ContentValues();
    values.put(Sms.TYPE, type);
    getContentResolver().update(uri, values, null, null);
}

private PendingIntent getSentIntent(Uri uri) {
    Log.i("txrjsms", "getSentIntent. Uri:"+uri);
   createSentReceiver();
    IntentFilter filter = new IntentFilter(TxrjConstant.ACTION_SEND_SMS);
    mContext.registerReceiver(sentReceiver, filter);
    Intent sentIntent = new Intent(TxrjConstant.ACTION_SEND_SMS);
    sentIntent.putExtra(TxrjConstant.EXTRA_SENT_URI, uri);
    return PendingIntent.getBroadcast(mContext, 0, sentIntent, 0);
}

7. 在getBroadcast方法中设置第4个参数Flag为PendingIntent.FLAG_UPDATE_CURRENT.

private PendingIntent getSentIntent(Uri uri) {
    Log.i("txrjsms", "getSentIntent. Uri:"+uri);    
    if(sentReceiver == null) {
        createAndRegisterSentReceiver();
    }
    Intent sentIntent = new Intent(TxrjConstant.ACTION_SEND_SMS);
    sentIntent.putExtra(TxrjConstant.EXTRA_SENT_URI, uri);
    return PendingIntent.getBroadcast(mContext, 0, sentIntent, PendingIntent.FLAG_UPDATE_CURRENT);
}

再查看日志。从日志可以反映出此时extra中的数据已经更新过。

07-16 14:15:53.096: I/txrjsms(7675): performSendMessage. Uri:content://sms/4019
07-16 14:15:53.106: I/txrjsms(7675): sendMessage. Uri:content://sms/4019
07-16 14:15:53.247: I/txrjsms(7675): getSentIntent. Uri:content://sms/4019
07-16 14:15:56.390: I/txrjsms(7675): sentReceiver. Uri:content://sms/4019
07-16 14:16:27.250: I/txrjsms(7675): performSendMessage. Uri:content://sms/4021
07-16 14:16:27.260: I/txrjsms(7675): sendMessage. Uri:content://sms/4021
07-16 14:16:27.270: I/txrjsms(7675): getSentIntent. Uri:content://sms/4021
07-16 14:16:29.612: I/txrjsms(7675): sentReceiver. Uri:content://sms/4021

8. PendingIntent中定义了几个FLAG。

(1) android.app.PendingIntent.FLAG_UPDATE_CURRENT

如果PendingIntent已经存在,保留它并且只替换它的extra数据。

int android.app.PendingIntent.FLAG_UPDATE_CURRENT = 134217728 [0x8000000]
Flag for use with getActivity, getBroadcast, and getService: 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.

(2) android.app.PendingIntent.FLAG_CANCEL_CURRENT

如果PendingIntent已经存在,那么当前的PendingIntent会取消掉,然后产生一个新的PendingIntent。

int android.app.PendingIntent.FLAG_CANCEL_CURRENT = 268435456 [0x10000000]
Flag for use with getActivity, getBroadcast, and getService: 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.

(3) android.app.PendingIntent.FLAG_ONE_SHOT

PendingIntent只能使用一次。调用了实例方法send()之后,它会被自动cancel掉,再次调用send()方法将失败。

int android.app.PendingIntent.FLAG_ONE_SHOT = 1073741824 [0x40000000]
Flag for use with getActivity, getBroadcast, and getService: 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.

(4) android.app.PendingIntent.FLAG_NO_CREATE

如果PendingIntent不存在,简单了当返回null。

int android.app.PendingIntent.FLAG_NO_CREATE = 536870912 [0x20000000]
Flag for use with getActivity, getBroadcast, and getService: if the described PendingIntent does not already exist, then simply return null instead of creating it.

9. android.app.PendingIntent.getBroadcast

取得一个PendingIntent,它会执行一个广播。效果就像Context.sendBroadcast()那样。

PendingIntent android.app.PendingIntent.getBroadcast(Context context, int requestCode, Intent intent, int flags)
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 by Intent.fillIn() to control which unspecified parts of the intent that can be supplied when the actual send happens.
Returns:
Returns an existing or new PendingIntent matching the given parameters. May return null only if FLAG_NO_CREATE has been supplied.

在发送信息时应用PendingIntent.FLAG_UPDATE_CURRENT的更多相关文章

  1. java在线聊天项目0.5版 解决客户端向服务器端发送信息时只能发送一次问题 OutputStreamWriter DataOutputStream socket.getOutputStream()

    没有解决问题之前客户端代码: package com.swift; import java.awt.BorderLayout; import java.awt.Color; import java.a ...

  2. linux上给其他在线用户发送信息(wall, write, talk, mesg)

        linux上给其他在线用户发送信息(wall, write, talk, mesg)   2018-01-05 lonskyMR 转自 恶之一眉 修改 微信分享: 设置登录提示     /et ...

  3. 利用MediaSession发送信息到蓝牙音箱

    1.利用MediaSession发送信息到蓝牙音箱,如:播放音乐时接收的歌曲信息,但是每一首歌连续播放时,再次发送的重复信息会被丢弃.则利用MediaSession发现信息时,要保证信息的不重复性. ...

  4. HTTP 请求方式: GET和POST的比较当发送数据时,GET 方法向 URL 添加数据;URL 的长度是受限制的(URL 的最大长度是 2048 个字符)。

    什么是HTTP? 超文本传输协议(HyperText Transfer Protocol -- HTTP)是一个设计来使客户端和服务器顺利进行通讯的协议. HTTP在客户端和服务器之间以request ...

  5. Linux常用命令 查看进程信息时 copy的-----温故而知新

    1.查进程    ps命令查找与进程相关的PID号:    ps a 显示现行终端机下的所有程序,包括其他用户的程序.    ps -A 显示所有程序.    ps c 列出程序时,显示每个程序真正的 ...

  6. [android]-如何在向服务器发送request时附加已保存的cookie数据

    [android]-如何在向服务器发送request时附加已保存的cookie数据 应用场景:在开发android基于手机端+服务器端的应用时,登陆->获取用户信息->获取授权用户相关业务 ...

  7. 基于nodejs+webSocket的聊天室(实现:加入聊天室、退出聊天室、在线人数、在线列表、发送信息、接收信息)

    1  安装 socket.io模块 npm install "socket.io": "latest" 2 app.js相关 ws = require('soc ...

  8. Microsoft Word 2007 向程序发送命令时出现问题解决方法

    最近在打开Word文档时总是出现“向程序发送命令时出现问题”对话框,而且不确定性,关闭重新打开有时没事了有时还不行, 很让人头疼,经过尝试,把问题解决了 1.问题截图如下: 2.解决方法 1)方法一: ...

  9. day29 python 套接字socket TCP udp 形式发送信息的区别

    我们经常把socket翻译为套接字,socket是在应用层和传输层之间的一个抽象层,它把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用已实现进程在网络中通信. socket起源于UNIX,在 ...

随机推荐

  1. iOS开发-CocoaPods实战

    CocoaPods 是开发 OS X 和 iOS 应用程序的第三方库的依赖管理工具,如果是正常的开发不需要使用的第三方的代码,CocoaPods是不需要的,但是从实际情况上,为了提高开发效率,Coco ...

  2. Android开发者选项 介绍

    15个必知的Android开发者选项 https://www.jianshu.com/p/07b551ee260b  1.Stay awake 充电时保持屏幕唤醒,开发的时候,时不时的锁屏真是够了,开 ...

  3. Mac系统下编译支持Android平台的最新X264编码器

    Mac系统下编译支持Android平台的最新X264编码器 原文来自 http://www.mingjianhua.com,转载请注明出处 1.首先去官网下载最新的x264源代码,解压到任意目录 ht ...

  4. -webkit-margin-before

    原文:https://www.cnblogs.com/guyw/p/4369653.html ----------------------------------------------- -webk ...

  5. Windows远程桌面连接的利器-mRemote

    mRemoteNG是Windows平台下一款开源的支持多标签.多协议的远程连接管理器.平时我们可能安装N多款管理工具,如putty.SecureCRT.xshell.SSHshell.mstsc.ex ...

  6. GIT 如何从另一分支合并特定的文件

    是否遇到过这种情景: 您在一个分支上工作,发现该分支上的某些文件实现的功能已经在其他分支上实现了 但因为这两个分支实现不同的功能,因此不能进行简单的合并工作,但您又不想重复其他已经完成的工作 以下操作 ...

  7. w3cscholl的在线代码编辑工具

    https://www.w3cschool.cn/tryrun/runcode?lang=c

  8. 原:wireshare使用技巧收集

    /data/local/tcpdump -p -vv -s 0 -w /sdcard/ThinkDrive.pcap     先抓一个pcap的包. 1. 查看所有的链接与流量 统计->对话 这 ...

  9. python绘制很美丽的图表

    或许你会觉得python不适合做图形界面的开发,的确如此.可是python却有一个非常美丽的图标模块:pycha,废话少说,先上图,各位看一下. 是不是效果还不错呢,当然这仅仅是一小部分图表,还有其它 ...

  10. UML关系(泛化,实现,依赖,关联(聚合,组合))

    http://www.cnblogs.com/olvo/archive/2012/05/03/2481014.html UML类图关系(泛化 .继承.实现.依赖.关联.聚合.组合) 继承.实现.依赖. ...