老版本的环信,实现消息撤回功能。
来源:互联网 发布:腾讯微信大数据 编辑:程序博客网 时间:2024/04/30 11:36
最近公司很久之前的一个集成过环信聊天功能的app,要增加消息撤回的功能,由于这个app是很久之前的。。所以,那个时候的easeUi里面并没有这个功能,于是就参照有这个功能的sdk,把代码搬了过来。。
Ps:当前的sdk版本是2.2.4
首先找到聊天页面ChatActivity页面,里面是一个EaseUi里面的EaseChatFragment,然后找到消息框点击事件,messageList有个item点击事件,(EaseChatMessageList.MessageListItemClickListener),有一系列事件,你可以写在消息框点击事件里(onBubbleClick),也可以写在消息框长按事件里面(onBubbleLongClick),我是选择了后者。
原理图:
参考链接:
http://docs.easemob.com/im/490integrationcases/revoke-messages
下面是效果图:
下面贴代码:
messageList.setItemClickListener(new EaseChatMessageList.MessageListItemClickListener() { @Override public void onUserAvatarClick(String username) { if (chatFragmentListener != null) { chatFragmentListener.onAvatarClick(username); } } @Override public void onResendClick(final EMMessage message) { new EaseAlertDialog(getActivity(), R.string.resend, R.string.confirm_resend, null, new AlertDialogUser() { @Override public void onResult(boolean confirmed, Bundle bundle) { if (!confirmed) { return; } resendMessage(message); } }, true).show(); } @Override public void onBubbleLongClick(EMMessage message) { contextMenuMessage = message; //这个是用来控制撤回这个菜单是否显示 boolean isvisibilty = false; /** * callback:这个用来判断是否已经是撤回的消息, * 在消息撤回以后,会发送一条新的消息,内容是XX * 撤回了一条消息(我暂且叫CallMessage) * 我在这个CallMessage中加了个扩展字段callback,来标识该条消息已经是 * 撤回的消息了。即再长按该条消息不需要再显示撤回这个菜单了 * */ boolean callback = false; try { callback = message.getBooleanAttribute("callback");//如果已经是撤回的消息了,就不要显示撤回这个选项了 } catch (EaseMobException e) { e.printStackTrace(); } /** * 这里需要判断下该条消息必须是自己发的,并且不是CallMessage * 才能显示撤回菜单 */ if (message.getFrom().equals(user.getHuanxinId()) && !callback) { isvisibilty = true; } else { isvisibilty = false; } //长按以后弹出一个选择框(包括复制消息,删除消息,和撤回消息) startActivityForResult((new Intent(getActivity(), ContextMenuActivity.class)) .putExtra("message", message) .putExtra("ischatroom", chatType == EaseConstant.CHATTYPE_CHATROOM) .putExtra("isvisibilty", isvisibilty), REQUEST_CODE_CONTEXT_MENU); } @Override public boolean onBubbleClick(EMMessage message) { if (chatFragmentListener != null) { return chatFragmentListener.onMessageBubbleClick(message); } return false; } });
选择框的样式:
下面是ContextMenuActivity.class(选择框)
import android.content.Intent;import android.os.Bundle;import android.view.MotionEvent;import android.view.View;import android.widget.TextView;import com.easemob.chat.EMMessage;import com.easemob.easeui.R;import com.easemob.easeui.utils.Constant;//import com.easemob.redpacketsdk.constant.RPConstant;//import com.hyphenate.chat.EMMessage;//import com.hyphenate.chatuidemo.Constant;//import com.hyphenate.chatuidemo.R;/** * 选择框页面,根据不同的type,来配置不同的布局,因为有的不需要有复制消息这个菜单 */public class ContextMenuActivity extends EaseBaseActivity { public static final int RESULT_CODE_COPY = 1; public static final int RESULT_CODE_DELETE = 2; public static final int RESULT_CODE_FORWARD = 3; public static final int RESULT_CODE_RECALL = 4; private EMMessage message; Intent intent; boolean isVisibilty;//撤回是否可见 private TextView tvReCall; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); intent=getIntent(); message = intent.getParcelableExtra("message"); isVisibilty=intent.getBooleanExtra("isvisibilty",false);// boolean isChatroom = getIntent().getBooleanExtra("ischatroom", false); int type = message.getType().ordinal(); if (type == EMMessage.Type.TXT.ordinal()) {// if(message.getBooleanAttribute(Constant.MESSAGE_ATTR_IS_VIDEO_CALL, false)// || message.getBooleanAttribute(Constant.MESSAGE_ATTR_IS_VOICE_CALL, false)// //red packet code : 屏蔽红包消息的转发功能// || message.getBooleanAttribute(RPConstant.MESSAGE_ATTR_IS_RED_PACKET_MESSAGE, false)){// //end of red packet code// setContentView(R.layout.em_context_menu_for_location);// }else if(message.getBooleanAttribute(Constant.MESSAGE_ATTR_IS_BIG_EXPRESSION, false)){ setContentView(R.layout.em_context_menu_for_image); }else{ setContentView(R.layout.em_context_menu_for_text); } } else if (type == EMMessage.Type.LOCATION.ordinal()) { setContentView(R.layout.em_context_menu_for_location); } else if (type == EMMessage.Type.IMAGE.ordinal()) { setContentView(R.layout.em_context_menu_for_image); } else if (type == EMMessage.Type.VOICE.ordinal()) { setContentView(R.layout.em_context_menu_for_voice); } else if (type == EMMessage.Type.VIDEO.ordinal()) { setContentView(R.layout.em_context_menu_for_video); } else if (type == EMMessage.Type.FILE.ordinal()) { setContentView(R.layout.em_context_menu_for_location); } tvReCall= (TextView) findViewById(R.id.recall); if(isVisibilty){ tvReCall.setVisibility(View.VISIBLE); }else{ tvReCall.setVisibility(View.GONE); }// if (isChatroom// //red packet code : 屏蔽红包消息的撤回功能// || message.getBooleanAttribute(RPConstant.MESSAGE_ATTR_IS_RED_PACKET_MESSAGE, false)) {// //end of red packet code// View v = (View) findViewById(R.id.forward);// if (v != null) {// v.setVisibility(View.GONE);// }// } } @Override public boolean onTouchEvent(MotionEvent event) { finish(); return true; } public void copy(View view){ setResult(RESULT_CODE_COPY); finish(); } public void delete(View view){ setResult(RESULT_CODE_DELETE); finish(); } public void forward(View view){ setResult(RESULT_CODE_FORWARD); finish(); } public void recall(View view){ setResult(RESULT_CODE_RECALL); finish(); }}
下面是布局:em_context_menu_for_image:
<?xml version="1.0" encoding="UTF-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="20dp" android:layout_marginRight="20dp" android:gravity="center_horizontal" android:orientation="vertical" > <!-- <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="1dp" android:background="@drawable/em_context_menu_item_bg" android:clickable="true" android:gravity="center_vertical" android:onClick="copy" android:padding="10dp" android:text="@string/copy" android:textColor="@android:color/black" android:textSize="20sp" /> --> <View android:layout_width="match_parent" android:layout_height="1px" android:background="@android:color/darker_gray" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/em_context_menu_item_bg" android:clickable="true" android:gravity="center_vertical" android:onClick="delete" android:padding="10dp" android:text="@string/delete" android:textColor="@android:color/black" android:textSize="20sp" /> <View android:layout_width="match_parent" android:layout_height="1px" android:background="@android:color/darker_gray" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/forward" android:background="@drawable/em_context_menu_item_bg" android:clickable="true" android:gravity="center_vertical" android:onClick="forward" android:padding="10dp" android:text="@string/forward" android:visibility="gone" android:textColor="@android:color/black" android:textSize="20sp" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/recall" android:background="@drawable/em_context_menu_item_bg" android:clickable="true" android:gravity="center_vertical" android:onClick="recall" android:padding="10dp" android:text="@string/recall" android:textColor="@android:color/black" android:textSize="20sp" /></LinearLayout>
其他的布局大同小异,就不一一贴出来了。
然后选择好是哪个菜单以后,选择框消失,回到聊天界面,
即EaseChatFragment的onActivityResult里面。。
if (requestCode == REQUEST_CODE_CONTEXT_MENU) { switch (resultCode) { case ContextMenuActivity.RESULT_CODE_COPY: // copy// MessageBody body = contextMenuMessage.getBody(); EMMessage.Type type = contextMenuMessage.getType(); if (type.equals(EMMessage.Type.TXT)) { TextMessageBody txtBody = (TextMessageBody) contextMenuMessage.getBody(); clipboard.setText(txtBody.getMessage()); } break; case ContextMenuActivity.RESULT_CODE_DELETE: // delete conversation.removeMessage(contextMenuMessage.getMsgId()); messageList.refresh(); break; case ContextMenuActivity.RESULT_CODE_FORWARD: // forward break; case ContextMenuActivity.RESULT_CODE_RECALL://撤回 recall(); break; default: break; } }
重点看下recall()方法,这个就是撤回功能。
/** * 撤回 * 原理: * A用户发送消息。 * A用户需要撤回某条消息,将消息id通过扩展消息发送到用户B。 * B用户收到扩展消息,解析其中的messageid,从数据库删除对应消息。 */ private void recall() {// sendTextMessage(); EMMessage cmdMsg = EMMessage.createSendMessage(EMMessage.Type.CMD);// 如果是群聊,设置chattype,默认是单聊 if (chatType == EaseConstant.CHATTYPE_GROUP) { cmdMsg.setChatType(ChatType.GroupChat); } else if (chatType == EaseConstant.CHATTYPE_CHATROOM) { cmdMsg.setChatType(ChatType.ChatRoom); } String action = "REVOKE_FLAG"; CmdMessageBody cmdBody = new CmdMessageBody(action);// 设置消息body cmdMsg.addBody(cmdBody);// 设置要发给谁,用户username或者群聊groupid cmdMsg.setReceipt(toChatUsername);// 通过扩展字段添加要撤回消息的id cmdMsg.setAttribute("msgId", contextMenuMessage.getMsgId()); cmdMsg.setAttribute("name", user.getName()); EMChatManager.getInstance().sendMessage(cmdMsg, new EMCallBack() { @Override public void onSuccess() {// Log.e("zmm","发送成功-->"); /** * 注意这里一定要把需要撤回的消息删除,这里如果不删除,会出现, * 自己这边的聊天列表里面该条消息还在。 */ //发送成功以后再这里把该撤回的消息删除,这里是为了刷新自己的聊天页面 conversation.removeMessage(contextMenuMessage.getMsgId());// Log.e("zmm", "删除消息-->" + contextMenuMessage.getMsgId()); EMMessage message = EMMessage.createTxtSendMessage(user.getName() + "回撤一条消息", toChatUsername); message.setAttribute("callback", true); sendMessage(message, user.getName()); } @Override public void onProgress(int progress, String status) { } @Override public void onError(int code, String error) { Log.e("zmm", "发送失败-->" + code + "-->" + error); } }); messageList.refreshSelectLast(); }
protected void sendMessage(EMMessage message, String name) { if (chatFragmentListener != null) { //设置扩展属性 chatFragmentListener.onSetMessageAttributes(message); } // 如果是群聊,设置chattype,默认是单聊 if (chatType == EaseConstant.CHATTYPE_GROUP) { message.setChatType(ChatType.GroupChat); } else if (chatType == EaseConstant.CHATTYPE_CHATROOM) { message.setChatType(ChatType.ChatRoom); } message.setAttribute("name", name);//这里放入发送人的名字,在需要拿到发送者名字的时候再取出来。(XX) //发送消息 EMChatManager.getInstance().sendMessage(message, null); //刷新ui messageList.refreshSelectLast(); }
然后就是在接收到该条CallMessage的地方处理下就可以了。
还是再EaseChatFragment这个页面,实现了EMEventListener这个接口,里有接收到新消息的回调:
{ EMMessage message = (EMMessage) event.getData();// Log.e("zmm","onEvent-->"+event.getEvent()); switch (event.getEvent()) { case EventNewMessage: // 获取到message String username = null; // 群组消息 if (message.getChatType() == ChatType.GroupChat || message.getChatType() == ChatType.ChatRoom) { username = message.getTo(); } else { // 单聊消息 username = message.getFrom(); } // 如果是当前会话的消息,刷新聊天页面 if (username.equals(toChatUsername)) { messageList.refreshSelectLast(); // 声音和震动提示有新消息 EaseUI.getInstance().getNotifier().viberateAndPlayTone(message); } else { // 如果消息不是和当前聊天ID的消息 EaseUI.getInstance().getNotifier().onNewMsg(message); } break; case EventDeliveryAck: case EventReadAck: // 获取到message messageList.refresh(); break; case EventOfflineMessage: // a list of offline messages // List<EMMessage> offlineMessages = (List<EMMessage>) // event.getData(); messageList.refresh(); break; case EventNewCMDMessage: // CMD消息(这个就是CallMessage返回的type)// Log.e("zmm", "接收到回调消息-->"); CmdMessageBody cmdMsgBody = (CmdMessageBody) message.getBody(); String action = cmdMsgBody.action;//获取自定义action String name = null; try { name = message.getStringAttribute("name"); } catch (EaseMobException e) { Log.e("zmm", "-->" + e.toString() + "-->" + e.getMessage()); e.printStackTrace(); } if (action.equals("REVOKE_FLAG")) { try { String msgId = message.getStringAttribute("msgId"); EMConversation conversation = EMChatManager.getInstance().getConversation(message.getFrom());// --删除消息来表示撤回--// Log.e("zmm",) conversation.removeMessage(msgId);// Log.e("zmm", "删除消息-->" + msgId); //删除消息以后增加一条XX撤回了一条消息。 EMMessage newmessage = EMMessage.createTxtSendMessage(name + "回撤一条消息", toChatUsername); newmessage.setAttribute("callback", true); sendMessage(newmessage, name); } catch (EaseMobException e) { // TODO Auto-generated catch block Log.e("zmm", "1111-->" + e.toString() + "-->" + e.getMessage()); e.printStackTrace(); } } break; default: break; } }
以上就完成了消息撤回功能。。特此记录。望对大家有帮助。
最后献上一句最近喜欢的话:
最怕一生碌碌无为,还说难得平凡可贵。。。。
加油!!!
- 老版本的环信,实现消息撤回功能。
- layim的websocket消息撤回功能实现
- iOS 环信消息撤回
- 环信iOS消息撤回
- 如何阅读微信聊天时好友的撤回消息?技术老司机教你!
- iOS 环信消息撤回发送透传消息的一些坑
- 让你的微信不再被人撤回消息
- xposed 微信消息 防撤回
- 微信消息防撤回工具
- 撤回的实现
- 微信防撤回的实现
- Mac QQ 防撤回------------------简单实现防女朋友撤回消息(好吧程序员哪有女朋友,我瞎说的....)
- 为什么微信撤回消息需要在2分钟以内?(大数据的应用)
- 工作流系统之三十三 撤回的实现
- 环信app的推送功能实现
- 教你如何使用微信网页版“抓取”微信撤回消息
- Android-IM即时通讯关于消息撤回的处理
- git撤回已经push到远端的版本
- 闪电狗 发送邮件 配置
- 使用HttpClient实现文件的上传下载
- java创建线程的两种方法
- leetcode 36. Valid Sudoku 数独有效
- Ajax比较
- 老版本的环信,实现消息撤回功能。
- linux ifconfig 查看网卡
- springMVC系列(七)——springMVC实现restful风格开发(post、get、put、delete)
- libvirt KVM
- 动画收集
- 判断光驱是否可读
- eclipse中java/xml自动提示功能实现
- ZZULIOJ 2133 密室逃脱【思维+字典树】
- SSM项目-对SpringMVC项目进行了整合