Android学习笔记:浅析自己的聊天系统的设计思想

在如今这个资料多如牛毛、牛人多于资料的社会,通过代码来做出某个东西已经渐渐不是很难的事情了,稍微有点难题只要一上各种专业论坛、各种技术群组,大家便会讨论的热火朝天,想不解决都难。技术我们可以学会,但是思想却很难,同样的一本书在不同的人看完之后都有不同的体会和感悟,那些牛人的思想都是在经历了无数浩浩的代码之后才体现出来(所以我们佩服那些公布自己心血的大牛,这种奉献精神是我们需要学习的),如何能快速的领悟牛人们的设计思想,对于像我们这样的菜鸟而言无疑是巨大的困难,正是有了大牛们的无私奉献,我们的学习注定会事半功倍,我们不需要魔鬼般代码的训练也可以领会高深的思想,使我们受益无穷。

本着学习的态度,且为了记录自己的感悟,在此分析一下开发过的一个聊天应用的设计思想,方便以后复习回顾。

通信协议UDP,关于这个在此便不多阐述。

通过下面这个简单的图,来分析一下是如何设计的:

由上图可以看出,整个系统分为7大模块,视图、消息处理器、消息解析器、UDP服务、解析控制器、处理控制器,消息体。

其中整个流程顺序:

1、首先我们在Activity中注册一个消息处理器,该处理器用来处理接收到的消息,然后将结果显示在Activity中;

2、发送消息的时候,我们要将自己的信息封装成一个消息包

3、该消息包要通过udp传输的话,还需要经过特定的解析器进行解析,得到一段传输协议,当然解析器中有编码肯定也有解码,且必须规则一样。

4、将上面得到的一段传输协议在此处理分析

5、调用解析控制器

6、解析控制器会通过协议中的一些标志,调用相应的解析器来进行解码得到响应的消息包。

7、调用处理控制器,同时将上面得到的响应消息包传过来

8、通过响应消息包中的一些标志,来判断调用相应的处理器来进行处理,得到信息然后显示。

注意:

1、消息msg有很多种,比如有向网段发送的询问谁在线的消息包、有响应谁在线的消息包、有聊天消息包、有个人信息查看请求消息包等等等等。

例如,谁在线消息包WhoOnlinePackage:

public class WhoOnlinePackage extends MsgPackage{ private String mac ; private String nickName; private int portrait; @Override public Integer getMsgCode() { return MsgCode.WHOONLINE; } public WhoOnlinePackage(String nickName, String mac,int portrait) { this.mac = mac; this.nickName = nickName; this.portrait = portrait; } public String getMac() { return mac; } public void setMac(String mac) { this.mac = mac; } public String getNickName() { return nickName; } public void setNickName(String nickName) { this.nickName = nickName; } public int getPortrait() { return portrait; } public void setPortrait(int portrait) { this.portrait = portrait; } public WhoOnlinePackage() {} }


2、消息包有多少种,就有多少种解析器,每个解析器针对不同的msg做不同的编码和解码工作。

例如:谁在线消息包解析器:

public class WhoOnlinePackageParser extends MsgPackageParser<WhoOnlinePackage>{ @Override public WhoOnlinePackage decode(PackageInputStream in) throws IOException { return new WhoOnlinePackage(in.readString(10, CHARSET),MsgPackageUtils.getLongMacToString(in.readLong()),in.readInt()); } @Override public void encode(WhoOnlinePackage obj, PackageOutputStream out) throws IOException { out.writeString(obj.getNickName(), 10); out.writeLong(MsgPackageUtils.getStringMacToLong(obj.getMac())); out.writeInt(obj.getPortrait()); } }

可以看到解析器中,编码和解码都是根据传输协议的规则来进行相应的处理。

3、同样有多少种解析器,就有多少种处理器。处理器根据解析器解析出来的消息包然后进一步进行处理,得到结果进行显示。

例如,在Activity中的处理器的实现:

@Override public void onMsgReceived(MsgPackage msgPackage) { switch (msgPackage.getMsgCode()) { case MsgCode.WHOONLINE: WhoOnlinePackage wpck = (WhoOnlinePackage)msgPackage; //得到别人询问谁在线的消息包 ImOnlinePackage ipck = new ImOnlinePackage(preferences.getString("nick", DicqConstant.LOCALNAME),preferences.getString("mac",DicqConstant.DEFAULTMAC),preferences.getInt("portrait",getLocalInfo().getPortrait())); //回应他我在线的消息包,同时把本地信息封装 ipck.addTargetIp(wpck.getFromIp()); sendMsgPackage(ipck, wpck.handlerTag); int wteamid = -1; Team wteam = service.getTeamByMac(wpck.getMac()); if(wteam==null){ try { wteamid = service.find("weimingming").getTeamId(); } catch (Exception e) { e.printStackTrace(); } }else{ wteamid = wteam.getTeamId(); } UserInfo wuser = new UserInfo(); wuser.setTeamid(wteamid); wuser.setUserip(wpck.getFromIp()); wuser.setUsermac(wpck.getMac()); wuser.setUsername(wpck.getNickName()); wuser.setPortrait(wpck.getPortrait()); wuser.setPersonsign("哥只是个传说"); //将信息封装成user对象 service.saveUserMac(wpck.getMac(), wteamid); addUserToList(wuser); if(!wpck.getMac().equalsIgnoreCase(DicqConstant.DEFAULTMAC)){ Toast.makeText(TeamMainActivity.this, wuser.getUsername()+"上线了!", Toast.LENGTH_LONG).show(); } adapter.setData(service.getTeamList(), userList); adapter.notifyDataSetChanged(); //刷新,显示 break;


4、解析控制器和处理控制器不用关注所有的解析器和处理器,通过一个标志来关注自己感兴趣的解析和处理器。这个解析在Activity的时候就已经注册的。

例如:注册解析器,Activity中:

@Override public void onServiceConnected() { register(MsgCode.WHOONLINE, -1); //注册询问谁在线解析器 register(MsgCode.IONLINE,-1); //注册响应谁在线解析器 register(MsgCode.SINGLECHAT,-1); //注册单聊解析器 register(MsgCode.IMGOAWAY,-1); //注册离线解析器 }


解析控制器:

** * 消息解析控制器 * */ public abstract class MsgPackageParserController { /** * 解析消息 * @param buf * @param offset * @param length * @return */ public abstract MsgPackage messageDecode(PackageInputStream in) throws IOException; /** * 编码消息 * @param command * @return */ public abstract void messageEncode(MsgPackage command,PackageOutputStream out) throws IOException; }


处理控制器:

/** * 消息处理控制器 * */ public abstract class MsgPackageProcessor { /** * 注册消息处理器 * @param handler * @param tag 处理器的标识,该标识起着维护不同设备同种消息的会话作用 */ public abstract void registMessageHandler(MsgPackageHandler<MsgPackage> handler,Integer tag); /** * 注销消息处理器 * @param msgCode 处理器感兴趣的消息类型 * @param tag 处理器的标识,该标识起着维护不同设备同种消息的会话作用 */ public abstract void unRegistMessageHandler(Integer msgCode,Integer tag); /** * 处理消息 * @param msgPackage */ public abstract void processMessage(MsgPackage msgPackage); }

5、传输协议很重要,这点根据个人理解不同制定不同的传输协议

6、udp server负责调度的作用,当消息来临时,调用解析控制器来生成一个相应的解析器解析消息得到一个消息包,然后交给处理控制器来生成一个相应的处理器处理解析器生成的消息包。关键代码如下:

/* * 消息循环 */ @Override public void run() { isrun=true; while(isrun && !socket.isClosed()){ byte[] buf=new byte[MAXBUFFSIZE]; DatagramPacket packet=new DatagramPacket(buf, MAXBUFFSIZE); try { socket.receive(packet); processUnresolvedMessage(buf,0,packet.getLength(),packet.getAddress()); } catch (IOException e) { e.printStackTrace(); } } } /** * 解析从远程发到的消息,并处理 * 消息解析控制器:解析消息 * 消息处理控制器:处理消息 */ @Override public void processUnresolvedMessage(byte[] msgPackage,int offset,int length,InetAddress fromIp) { MsgPackage m=null; try { m=messageParser.messageDecode(new PackageInputStream(msgPackage, offset, length)); //解析成消息包 } catch (Exception e) { Log.e(TAG, "command decode exception", e); } if(m!=null){ m.setFromIp(fromIp); messageProcessor.processMessage(m); //交给处理器处理 return; } Log.w(TAG, "Unresolved Message:from "+fromIp+" Data:"+Arrays.toString(msgPackage)); }



暂时先总结到这里,日后想到在更新吧。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值