安卓聊天软件
设计模式
public class OnMap {
private HashMap<Integer, ClientActivity>clientMap;
private static OnMap instance;//此静态实例类加载完成后就一直存在
public static OnMap getInstance() {
if (instance==null)
instance=new OnMap();
return instance;
}
private OnMap() {
clientMap=new HashMap<Integer, ClientActivity>();
}
}
采用单例模型,此时线程是不安全的,(访问量较小时可忽略)因为当instance为null时,如果A和B同时访问,就会产生两个实例。可以给其加上锁,使其线程安全。
public class OnMap {
private HashMap<Integer, ClientActivity>clientMap;
private static OnMap instance;//此静态实例类加载完成后就一直存在
public static OnMap getInstance() {
if (instance==null)
synchronized (OnMap.class) {
if (instance == null) {
instance=new OnMap();
}
}
return instance;
}
private OnMap() {
clientMap=new HashMap<Integer, ClientActivity>();
}
}
1.数据库设计:
id使用AUTO_INCREMENT保证唯一编号。
2.功能介绍:
2.1登录
输入账号和密码之后即登录,新用户则点击右下方按钮进行注册。
2.2注册
初次进入该界面会申请照片的权限,可以通过现在拍摄和图库中选择照片两种方式设置头像。用户的账号是自动生成的。
2.2.1如何自动生成不重复账号
public static String randomNumber(int num) {
Random random = new Random();
StringBuilder str = new StringBuilder();
for (int i = 0; i < num; i++) {
str.append(random.nextInt(9));
}
return str.toString();
}
生成一个num位的随机字符串。当同时申请的人数较少时,此时生成的字符串基本都是不一样的。
2.2.2如何判断客户端是进行登录还是注册
public enum TranObjectType {
REGISTER, // 注册
LOGIN, // 用户登录
MESSAGE, // 用户发送消息
SEARCH_FRIEND,//找朋友
FRIEND_REQUEST;//好友申请
}
使用一个枚举类,列出所有的可能,在Listen监听线程中用case判断消息类型。
2.2.3如何确保数据库的插入语句是否执行完毕
try {
//传入一个false,这样将不会自动提交,而需要使用con.commit()方法,手动提交事务,
con.setAutoCommit(false);
} catch (SQLException e) {
// TODO: handle exception
e.printStackTrace();
}
PreparedStatement ps;
try {
ps=con.prepareStatement(sql0);
ps.execute();
ps=con.prepareStatement(sql1);
ps.setString(1, user.getAccount());
ps.setString(2, user.getUserName());
ps.setBytes(3, user.getPhoto());
//System.out.println("照片长度为"+user.getPhoto().length);
ps.setDate(4, new java.sql.Date(user.getBirthday().getTime()));
ps.setString(5, user.getPassword());
ps.setInt(6, user.getGender());
System.out.println("语句为"+sql1);
ps.executeUpdate();
con.commit();
} catch (SQLException e) {
// TODO: handle exception
try {
System.out.println("插入数据库异常,正在进行回滚....");
con.rollback();
} catch (Exception e2) {
// TODO: handle exception
e2.printStackTrace();
}
e.printStackTrace();
}
使用事务,确保语句能正确执行,否则回滚。
2.3添加好友
通过好友的账号来搜索,输入对方的账号后,就点击查找,就进入了该界面。
此时,对方点击该条消息后,会弹出一个对话框。
2.3.1 如何将好友结果发送到客户端
public class TranObject implements Serializable {
private static final long serialVersionUID=1L;
private Object object;
private TranObjectType tranType;
private Result result;
private String sendTime;
private int sendId;
private int receiveId;
private String sendName;
}
将目标序列化之后发送,在客户端进行反序列化。
2.4收发消息
2.4.1如何处理多人向同一个好友发信息
private LinkedList<TranObject> sendQueue;
public synchronized void insertQueue(TranObject tran) {
sendQueue.add(tran);
}
使用一个队列sendQueue来维护所有人向该用户发送的消息,用synchronized修饰,保证每次只能有一个用户将消息加入到消息队列之中。
服务器会实时检测sendQueue的大小,当sendQueue的大小不为0的时候,向客户端转发消息。
2.4.1实时转发与离线转发
public void sendFriend(TranObject tran) {
ClientActivity friendClient = null;
if (mServer.contatinId(tran.getReceiveId())) {
friendClient = mServer.getClientByID(tran.getReceiveId());
friendClient.insertQueue(tran);
} else {
SaveMsgDao.insertSaveMsg(user.getId(), tran);
}
}
当好友在线的时候,转发的消息不存入数据库,而是直接转发给对方,增加实时性,客户端通过handler来更新UI。当好友不在线的时候。存入数据库,当好友上线的时候,会自动读取离线消息,读取之后用SQLite存储在本机。读取之后,服务器端的数据库会删除他的所有离线信息。