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. 创建SQL作业错误的解决方法(不能将值 NULL 插入列 'owner_sid',表 'msdb.dbo.sysjobs';列不允许有空值。)

    在用SQL语句创建SQL Server作业时有时出现如下错误: 消息 515,级别 16,状态 2,过程 sp_add_job,第 137 行 不能将值 NULL 插入列 'owner_sid',表  ...

  2. 【Spark】SparkStreaming-流处理-规则动态更新-解决方案

    SparkStreaming-流处理-规则动态更新-解决方案 image2017-10-27_11-10-53.png (1067×738) elasticsearch-head Elasticsea ...

  3. 一文读懂「Attention is All You Need」| 附代码实现

    https://mp.weixin.qq.com/s?__biz=MzIwMTc4ODE0Mw==&mid=2247486960&idx=1&sn=1b4b9d7ec7a9f4 ...

  4. 前端笔记----jquery入门知识点总结 (转)

    http://www.cnblogs.com/cwp-bg/p/7633623.html 一.jquery的加载方法 $(document).ready(function(){js代码}); $(fu ...

  5. 我的四轴专用PID参数整定方法及原理---超长文慎入(转)

    给四轴调了好久的PID,总算是调好了,现分享PID参数整定的心得给大家,还请大家喷的时候手下留情. 首先说明一下,这篇文章的主旨并不是直接教你怎么调,而是告诉你这么调有什么道理,还要告诉大家为什么'只 ...

  6. ueditor插入自定义内容和样式

    UEditor是由百度web前端研发部开发所见即所得富文本web编辑器,具有轻量,可定制,注重用户体验等特点   通过UEditor提供的API接口可以很方便的读写操作内容并设置编辑器里的样式   页 ...

  7. 模拟日历计算 poj1008

    Maya Calendar Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 69932   Accepted: 21524 D ...

  8. C# winForm webBrowser页面中js调用winForm类方法(转)

      有时我们在winform项目中嵌入了网页,想通过html页面调用后台方法,如何实现呢?其实很简单,主要有三部:   1.在被调用方法类上加上[ComVisible(true)]标签,意思就是当前类 ...

  9. notepad++列块编辑操作

    1. 同一时候编辑连续的列区域: 鼠标先在要进行列编辑的起点点击,再同一时候按shift+alt不放,鼠标在要进行列编辑的结尾区域点击. 2. 在起点到文档结尾全部列插入数据: 鼠标先在要插入数据的位 ...

  10. 【Android界面实现】使用PagerTabStrip实现有滑动标签的Viewpager

    在ViewPager这样的能够滑动的控件上,总是有非常多的文章能够做.上次的文章,我们实现了一个自己定义的ViewPager的指示器,这篇文章,我们主要是想利用Android自带的控件,实现一个指示器 ...