項目源碼請參考 Android-IM
項目服務端使用極光JMessage
對話撤回的效果圖:
這里只是在對話的界面展示了撤回消息的處理。
其實還有一個地方蝗锥,是會話列表葱蝗,也需要動態(tài)展示撤回消息的通知悼凑。
先說對話列表要進行的操作
- 發(fā)送方:點擊撤回事件寸莫,本地視圖移除披坏,通知服務端更新
- 接收方:動態(tài)獲取消息帚屉,當獲取到撤回消息事件,移除視圖槽袄。
然后是會話列表也要同步展示
- 會話列表只有一個接收方,需要在接收到撤回消息的事件更新視圖
具體實現(xiàn)
發(fā)送方撤回
只能是發(fā)送方才可以撤回
1多搀、首先獲取當前聊天的會話
position這里是從上個頁面?zhèn)鬟f的數(shù)據(jù),上個頁面是指會話列表的索引懊蒸。Conversation就是當前的會話菊碟。
JMessageClient.getConversationList()是獲取所有的會話列表。
Conversation conversation=JMessageClient.getConversationList().get(position);
2靡馁、創(chuàng)建撤回事件
這個事件就是通知服務端的撤回消息结缚。
兩個參數(shù)分別是(需要撤回的消息,服務端返回的結果)稀火。其中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第二個參數(shù)是消息類型
完整代碼:
//
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);
}
}
});
獲取對方的撤回事件
撤回的目的就是為了讓對方看不到姚淆,而我們作為發(fā)送方媒惕,當收到對方的消息之后,默認是直接在對話窗口展示的但壮。但是這時候對方突然撤回了消息,我們也需要在對話窗口移除掉消息哩盲。
1趣竣、注冊消息接收者
所有的通知码秉,消息都需要注冊汞窗。包括消息事件模捂、撤回事件综看、好友請求事件等等。
注冊的方法是在onCreate中忠寻,一般在android開發(fā)中會定義一個BaseActivity的基類
或者單獨的Activity中也一樣纵朋,添加:
JMessageClient.registerEventReceiver(this);
這里有個需要注意的是收到消息的時候,通知欄也會顯示消息雄家,所以如果是在對話界面,需要關閉通知欄的通知:
userName就是當前對話的對方的用戶名趟济,一般在上個頁面通過數(shù)據(jù)傳遞的方式獲取
JMessageClient.enterSingleConversation(userName);
2乱投、接收撤回消息
onEvent是為了方便JMessage識別的方法,是固定的顷编,里面的參數(shù)如果是接收撤回的消息就是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的第二個參數(shù)就需要改變?yōu)閷Ψ降念愋土恕?br> 在加載消息列表的時候也是通過該方法來判斷消息展示的左右位置。
但是會有一個問題贮庞,因為移除視圖是通過獲取消息存在本地的id峦筒。
當連續(xù)從服務器獲取幾條消息的時候,如果要撤回其中的一條窗慎。還需要對所有的消息遍歷物喷,并且判斷服務端返回的消息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是我們一開始進入頁面獲取的消息列表扇丛。同時要在獲取新消息的事件中動態(tài)添加到集合中。否則當對方發(fā)起撤回的時候尉辑,本地無法更新視圖帆精。
完整代碼:
/*接收到撤回的消息*/
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()是獲取會話列表的方法购啄,也就是當前頁面展示的內(nèi)容襟企。
該方法是封裝后存在于本地的,所以不需要做進一步的處理狮含。
只是加載后做進一步的解析-展示處理就行了顽悼。
1、解析會話列表
解析相對于來說比較簡單几迄,解析需要的實體類可以自己創(chuàng)建蔚龙。將需要用到的參數(shù)解析出來就可以了。
在接收到撤回消息的時候或者其他消息乓旗,需要我們刷新數(shù)據(jù)府蛇。
這里需要注意的是在解析消息的時候,要對其做判斷屿愚,由于目前只設置了文字消息和撤回消息兩種,所以暫時只對這兩種消息做了額外的處理务荆。
后期還需要對圖片消息妆距,語音消息等做進一步的判斷。
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() {
//重新加載數(shù)據(jù)
updataData();
}
},500);
}
總結
在做消息功能的時候盅惜,大多數(shù)都是參照文檔來開發(fā)中剩,所以做的時候,需要對相關的類有一定的了解抒寂。知道其用法结啼。
而且會話也是一個即時通訊的最基礎的功能。涉及的范圍也比較廣屈芜,目前項目只實現(xiàn)了文字的會話郊愧,更高級的對話方式還需要進一步的開發(fā)朴译。
項目地址:https://github.com/wapchief/Android-IM
相關閱讀推薦: