Android-IM即时通讯关于消息撤回的处理

项目源码请参考 Android-IM
项目服务端使用极光JMessage

对话撤回的效果图:

这里只是在对话的界面展示了撤回消息的处理。
其实还有一个地方,是会话列表,也需要动态展示撤回消息的通知。

先说对话列表要进行的操作

  • 发送方:点击撤回事件,本地视图移除,通知服务端更新
  • 接收方:动态获取消息,当获取到撤回消息事件,移除视图。

然后是会话列表也要同步展示

  • 会话列表只有一个接收方,需要在接收到撤回消息的事件更新视图

具体实现

发送方撤回

只能是发送方才可以撤回

1、首先获取当前聊天的会话

position这里是从上个页面传递的数据,上个页面是指会话列表的索引。Conversation就是当前的会话。
JMessageClient.getConversationList()是获取所有的会话列表。

Conversation conversation=JMessageClient.getConversationList().get(position);

2、创建撤回事件

这个事件就是通知服务端的撤回消息。
两个参数分别是(需要撤回的消息,服务端返回的结果)。其中Message在长按消息的时候就给返回了,只需获取消息就可以了。
conversation.retractMessage(message.getMessage(), new BasicCallback())

3、接收到撤回成功的事件

当服务器返回撤回成功的事件(i==0)后,通过

//移除当前item
mAdapter.deleteById(message.getMsgId());
//添加一条撤回的item
mAdapter.addToStart(new MyMessage("[你撤回了一条消息]", SEND_TEXT),true);
//更新视图
mAdapter.notifyDataSetChanged();

new MyMessage第二个参数是消息类型

完整代码:

//
conversation.retractMessage(message.getMessage(), new BasicCallback() {
    @Override
    public void gotResult(int i, String s) {
        if (i==0){
            showToast(ChatMsgActivity.this,"撤回了一条消息");
            mAdapter.deleteById(message.getMsgId());
            mAdapter.addToStart(new MyMessage("[你撤回了一条消息]", SEND_TEXT),true);
            mAdapter.notifyDataSetChanged();
        }else {
            showToast(ChatMsgActivity.this,"撤回失败:"+s);
        }
    }
});

获取对方的撤回事件

撤回的目的就是为了让对方看不到,而我们作为发送方,当收到对方的消息之后,默认是直接在对话窗口展示的。但是这时候对方突然撤回了消息,我们也需要在对话窗口移除掉消息。

1、注册消息接收者

所有的通知,消息都需要注册。包括消息事件、撤回事件、好友请求事件等等。
注册的方法是在onCreate中,一般在android开发中会定义一个BaseActivity的基类
或者单独的Activity中也一样,添加:
JMessageClient.registerEventReceiver(this);
这里有个需要注意的是收到消息的时候,通知栏也会显示消息,所以如果是在对话界面,需要关闭通知栏的通知:
userName就是当前对话的对方的用户名,一般在上个页面通过数据传递的方式获取
JMessageClient.enterSingleConversation(userName);

2、接收撤回消息

onEvent是为了方便JMessage识别的方法,是固定的,里面的参数如果是接收撤回的消息就是MessageRetractEvent,如果是正常的会话消息就是MessageEvent,当然还有好友请求的消息ContactNotifyEvent等等。具体可以去查看api文档。

由于这个是独立的类,在移除视图的时候需要我们传一个消息id。
这个id的获取也需要在两个地方获取:
a) 在加载消息列表的时候,我们要把筛选出来正常的消息(非撤回)设置id。
b) 在接收到新消息时,也需要我们获取id。
需要注意的是被撤回的消息是没有ID的,不能再次被撤回
msgID = myMessage.getMsgId();

移除完视图之后,可以选择再添加一个新的撤回消息的视图

mAdapter.addToStart(new MyMessage("[对方撤回了一条消息]", IMessage.MessageType.RECEIVE_TEXT),true);

这里new MyMessage的第二个参数就需要改变为对方的类型了。
在加载消息列表的时候也是通过该方法来判断消息展示的左右位置。

但是会有一个问题,因为移除视图是通过获取消息存在本地的id。
当连续从服务器获取几条消息的时候,如果要撤回其中的一条。还需要对所有的消息遍历,并且判断服务端返回的消息id(messageId)和本地消息id(msgID)是否一致,当一致的时候撤回,并移除本地视图。

//日志
message:  Message{_id=7, messageId=413528998, createTimeInMillis=1504165079011, direct=receive, status=receive_success, content={"promptText":"1006自动回复机器人撤回了一条消息","extras":{}}, version=1, fromName='1006自动回复机器人', contentType=prompt, contentTypesString='prompt', targetType=single, targetID='null', targetName='null', fromType='user', atList=null, fromID=1006, notification=null, isSetFromName=0, suiMTime=0}
                                                                      
Mymessage:  MyMessage{id=-7007385618142453134, text='2', timeString='08-31 15:37', type=RECEIVE_TEXT, user=com.wapchief.jpushim.entity.DefaultUser@cc2c2e9, mediaFilePath='null', duration=0, progress='null', position=0, msgID=413528998}

这里的list是我们一开始进入页面获取的消息列表。同时要在获取新消息的事件中动态添加到集合中。否则当对方发起撤回的时候,本地无法更新视图。
完整代码:

    /*接收到撤回的消息*/
    public void onEvent(MessageRetractEvent event){
        final Message message = event.getRetractedMessage();
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                for (int i=0;i<=list.size();i++){
                    if (list.get(i).getMsgID()==message.getServerMessageId()){
                        mAdapter.delete(list.get(i));
                        MyMessage message1=new MyMessage("[对方撤回了一条消息]", IMessage.MessageType.RECEIVE_TEXT);
                        mAdapter.addToStart(message1,true);
                        mAdapter.notifyDataSetChanged();
                        mAdapter.updateMessage(message1);
                    }
                }
            }

        });

    }

3、注销消息接收者、退出会话

在onDestroy中

   @Override
    protected void onDestroy() {
         //接收事件解绑
        JMessageClient.unRegisterEventReceiver(this);
        //退出会话
        JMessageClient.exitConversation();
        super.onDestroy();
    }

上面就完成了对话消息列表的撤回处理。
接下来还有个地方需要处理。

会话列表接收撤回

效果图:



上面提到过JMessageClient.getConversationList()是获取会话列表的方法,也就是当前页面展示的内容。
该方法是封装后存在于本地的,所以不需要做进一步的处理。
只是加载后做进一步的解析-展示处理就行了。

1、解析会话列表

解析相对于来说比较简单,解析需要的实体类可以自己创建。将需要用到的参数解析出来就可以了。
在接收到撤回消息的时候或者其他消息,需要我们刷新数据。

这里需要注意的是在解析消息的时候,要对其做判断,由于目前只设置了文字消息和撤回消息两种,所以暂时只对这两种消息做了额外的处理。
后期还需要对图片消息,语音消息等做进一步的判断。

getLatestMessage()是获取最后一条消息的意思。

if (list.get(i).getLatestMessage().getContent().getContentType()== ContentType.prompt) {
                        bean.setContent(((PromptContent) (list.get(i).getLatestMessage()).getContent()).getPromptText());
                    }else {
                        bean.setContent(((TextContent) (list.get(i).getLatestMessage()).getContent()).getText());
                    }

部分代码:


for (int i = 0; i < list.size(); i++) {
                bean = new MessageBean();
                try {
                    //这里进行撤回消息的判断
//                    Log.e("type", list.get(i).getTitle()+","+list.get(i).getLatestMessage().getContent().getContentType());
                    if (list.get(i).getLatestMessage().getContent().getContentType()== ContentType.prompt) {
                        bean.setContent(((PromptContent) (list.get(i).getLatestMessage()).getContent()).getPromptText());
                    }else {
                        bean.setContent(((TextContent) (list.get(i).getLatestMessage()).getContent()).getText());
                    }
                } catch (Exception e) {
                        bean.setContent("最近没有消息!");
                    Log.e("Exception:MessageFM", e.getMessage());
                }
                bean.setMsgID(list.get(i).getId());
                bean.setUserName(((UserInfo) list.get(i).getTargetInfo()).getUserName());
                bean.setTitle(list.get(i).getTitle());
                bean.setTime(list.get(i).getUnReadMsgCnt() + "");
                bean.setConversation(list.get(i));
//                Log.e("Log:Conversation", list.get(i).getAllMessage()+"");

                try {
                    bean.setImg(list.get(i).getAvatarFile().toURI() + "");
                } catch (Exception e) {
                }
                data.add(bean);
            }
        }

        mFragmentMainRf.setRefreshing(false);
        adapter.notifyDataSetChanged();

2、接收撤回消息

和前面接收消息的方法一样

    /*接收撤回消息*/
    public void onEvent(MessageRetractEvent event) {
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                //重新加载数据
                updataData();
            }
        },500);
    }

总结

在做消息功能的时候,大多数都是参照文档来开发,所以做的时候,需要对相关的类有一定的了解。知道其用法。
而且会话也是一个即时通讯的最基础的功能。涉及的范围也比较广,目前项目只实现了文字的会话,更高级的对话方式还需要进一步的开发。

项目地址:https://github.com/wapchief/Android-IM

相关阅读推荐:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容

  • 点击查看原文 Web SDK 开发手册 SDK 概述 网易云信 SDK 为 Web 应用提供一个完善的 IM 系统...
    layjoy阅读 13,659评论 0 15
  • https://github.com/coderMyy/MYCoreTextLabel 图文混排 , 实现图片文...
    saman0阅读 2,932评论 1 19
  • ¥开启¥ 【iAPP实现进入界面执行逐一显】 〖2017-08-25 15:22:14〗 《//首先开一个线程,因...
    小菜c阅读 6,357评论 0 17
  • 关于聊天室项目 聊天室项目,也被称为即时通讯(IM)。 其原理是服务器是一直在启动状态的线程,不断的从客户端(Ap...
    八怪不姓丑阅读 41,493评论 52 241
  • 2017.02.22 可以练习,每当这个时候,脑袋就犯困,我这脑袋真是神奇呀,一说让你做事情,你就犯困,你可不要太...
    Carden阅读 1,325评论 0 1