【oschina android源码分析】聊天页面(私信)的设计
来源:互联网 发布:编程显示九九乘法表 编辑:程序博客网 时间:2024/05/21 10:09
一.总结
1.如何支持连续的消息发送,并且不会产生线程安全的问题
//存放正在发送的消息,key 为生成的一个临时messageID(msgTag),value为Message实体//当消息发送成功后,从mSendingMsgs删除对应的Message实体private SparseArray<MessageDetail> mSendingMsgs = new SparseArray<MessageDetail>();
2.一些分析
本设计应该是较为常见的聊天设计方案。其实近一年来,我也主要参与了公司聊天页面的开发和设计,本方案和我们公司的设计细节还是不太相符,不过整体的架构有很大的参考价值。
其实原理非常简单:就是一个listview,然后动态的修改listview中某个item的状态。
二.具体流程
1.点击发送按钮:
if (!AppContext.getInstance().isLogin()) { UIHelper.showLoginActivity(getActivity()); return; } if (StringUtils.isEmpty(str)) { AppContext.showToastShort(R.string.tip_content_empty); return; } MessageDetail message = new MessageDetail(); User user = AppContext.getInstance().getLoginUser(); int msgTag = mMsgTag++; message.setId(msgTag); message.setPortrait(user.getPortrait()); message.setAuthor(user.getName()); message.setAuthorId(user.getId()); message.setContent(str.toString()); sendMessage(message);
说明:
即每个消息都是有一个本地的id的,作为区分
2.发送消息调用的具体方法分析:
/** * 发送消息 * @param msg */ private void sendMessage(MessageDetail msg){ msg.setStatus(MessageDetail.MessageStatus.SENDING); Date date = new Date(); msg.setPubDate(net.oschina.app.util.StringUtils.getDateString(date)); //如果此次发表的时间距离上次的时间达到了 TIME_INTERVAL 的间隔要求,则显示时间 if(isNeedShowDate(date.getTime(),mLastShowDate)) { msg.setShowDate(true); mLastShowDate = date.getTime(); } //如果待发送列表没有此条消息,说明是新消息,不是发送失败再次发送的,不需要再次添加 if(mSendingMsgs.indexOfKey(msg.getId())<0) { mSendingMsgs.put(msg.getId(), msg); mAdapter.addItem(0, msg); mListView.setSelection(mListView.getBottom()); }else{ mAdapter.notifyDataSetChanged(); } OSChinaApi.publicMessage(msg.getAuthorId(), mFid, msg.getContent(), new SendMessageResponseHandler(msg.getId())); }
说明:
- 如果待发送消息列表中没有这条消息,则把消息加入到待发送消息列表中,并刷新聊天列表。
- 调用发送消息的网络请求接口。
3.发送接口具体实现操作:
class SendMessageResponseHandler extends AsyncHttpResponseHandler{ private int msgTag; public SendMessageResponseHandler(int msgTag) { this.msgTag = msgTag; } @Override public void onSuccess(int arg0, Header[] arg1, byte[] arg2) { try { ResultBean resb = XmlUtils.toBean(ResultBean.class, new ByteArrayInputStream(arg2)); Result res = resb.getResult(); if (res.OK()) { //从mSendingMsgs获取发送时放入的MessageDetail实体 MessageDetail message = mSendingMsgs.get(this.msgTag); MessageDetail serverMsg = resb.getMessage(); //把id设置为服务器返回的id message.setId(serverMsg.getId()); message.setStatus(MessageDetail.MessageStatus.NORMAL); //从待发送列表移除 mSendingMsgs.remove(this.msgTag); mAdapter.notifyDataSetChanged(); } else { error(); AppContext.showToastShort(res.getErrorMessage()); } emojiFragment.clean(); } catch (Exception e) { e.printStackTrace(); onFailure(arg0, arg1, arg2, e); } } @Override public void onFailure(int arg0, Header[] arg1, byte[] arg2, Throwable arg3) { error(); } private void error(){ mSendingMsgs.get(this.msgTag).setStatus(MessageDetail.MessageStatus.ERROR); mAdapter.notifyDataSetChanged(); } }
说明:
- 需要把消息的tag传递进来。
- 发送成功的话,从mSendingMsgs获取发送时放入的MessageDetail实体,把id设置为服务器返回的id,并改变本地消息的状态,并从待发送列表中删除本地消息,刷新列表。是不会从服务端再拉取一遍的。
- 发送失败的话,设置发送的消息的状态为失败,并刷新列表。
4.失败点击重发的实现方案:
采用的是接口回调的方案。
Adapter:
public interface OnRetrySendMessageListener { void onRetrySendMessage(int msgId); }
/** * 重试发送 * * @param v */ @OnClick(R.id.itv_error) void retry(View v) { if (v.getTag() != null && mOnRetrySendMessageListener != null) { mOnRetrySendMessageListener.onRetrySendMessage((int) v.getTag()); } } }
Fragment:该fragment实现了Adapter的重发接口
public class MessageDetailFragment extends BaseListFragment<MessageDetail> implements OnItemLongClickListener, OnSendClickListener,MessageDetailAdapter.OnRetrySendMessageListener
adapter.setOnRetrySendMessageListener(this);
@Override public void onRetrySendMessage(int msgId) { MessageDetail message = mSendingMsgs.get(msgId); if (message != null) { sendMessage(message); } }
5.每条消息的状态:
在实体中有一个发送状态的字段,通过不断修改该值来实现消息发送状态的切换。
0 0
- 【oschina android源码分析】聊天页面(私信)的设计
- 【oschina android源码分析】页面通知(站内信)的设计-android轮询方案
- 【oschina android源码分析】缓存的设计
- 【oschina android源码分析】登陆和退出的设计
- 【oschina android源码分析】下载更新新版本的设计
- 【oschina android源码分析】便笺系统的设计
- oschina的android源码分析学习(一)
- 【oschina android源码分析】总结
- oschina的android源码分析学习-MainActivity
- 【oschina android源码分析】切换夜间模式的实现
- OSChina客户端源码学习(2)--缓存的设计
- 分析开源oschina客户端的源码(一)
- oschina源码分析:架构篇(草稿)
- oschina源码分析:实现篇(草稿)
- OSChina Android 客户端源码
- oschina-app 的源码分析-主页面滑动切换
- 私信、留言功能的数据库设计
- oschina-app 源码分析-数据缓存(离线功能)
- windows 下安装RabbitMQ
- 【oschina android源码分析】便笺系统的设计
- 逆波兰表达式
- USB调试不能弹出授权窗口 unauthorized 的解决办法
- LAN中访问其它主机的jupyter/ipython
- 【oschina android源码分析】聊天页面(私信)的设计
- 一个用来判断是长按手势的辅助类
- 【oschina android源码分析】总结
- 计算机图形学(二)输出图元_12_OpenGL顶点数组
- 【android】ImageView的src和background的区别以及两者的妙用
- 集合的引入
- JSP03
- iOS开发常见的奇葩技巧,
- 常规功能和模块自定义系统 (cfcmms)—045模块导航功能的重构(3)导航的定义