Android实时绘制效果
一、概述
通过长连接的Socket通信,实时发送绘制信息给各客户端,以实现实时显示效果。
二、运行效果
三、功能代码
1
)通信部分
长连接的Socket通信,支持多客户端。服务器和客户端都可主动发送消息。消息的话,将Object转成了json字符串了。
之前用ObjectOutputStream多客户端传送对象时遇到了问题,又搜索了下,参见该网址:
http://blog.csdn.net/jsjboss/article/details/752193。也就是要建立了ObjectOutputStream的集合,来传消息了?总之,服务器通过Socket集合每次new个ObjectOutputStream来发消息是不成的!
ps:不想转json,还是想用ObjectOutputStream发送的,可参照《Java Socket通信》长连接通信内的对象消息样例。
1.1)EasyServer.java
- /**
- * 长连接、1对n主动发消息的服务器
- *
- * @author Join
- */
- public class EasyServer extends Thread {
- /** 退出命令 */
- public static final String EXIT_COMMAND = "end";
- /** 服务端口 */
- private int port;
- /** 服务套接字 */
- private ServerSocket mServerSocket;
- /** 线程池 */
- private ExecutorService pool;
- /** 客户端套接字集合 */
- private ArrayList<Socket> mClientList;
- /** 服务器监听接口 */
- private OnServerListener listener;
- public EasyServer(int port) {
- this.port = port;
- pool = Executors.newCachedThreadPool(); // 缓存线程池
- mClientList = new ArrayList<Socket>();
- }
- @Override
- public void run() {
- try {
- mServerSocket = new ServerSocket(port); // 创建本地特定端口服务器套接字
- Socket client = null;
- while (true) {
- client = mServerSocket.accept(); // 接收连接的套接字
- mClientList.add(client); // 加入客户端列表
- if (null != listener) {
- listener.onClientConnected(client.getInetAddress());
- }
- pool.execute(new ThreadServer(client)); // 新线程执行任务
- }
- } catch (BindException e) { // 端口使用中
- if (null != listener) {
- listener.onBindException();
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- /** 各个连接客户端的服务线程 */
- private class ThreadServer extends Thread {
- private Socket client;
- public ThreadServer(Socket client) {
- this.client = client;
- }
- @Override
- public void run() {
- DataInputStream in = null;
- try {
- in = new DataInputStream(client.getInputStream());
- while (true) {
- /* 接收数据消息 */
- String msg = in.readUTF();
- if (EXIT_COMMAND.equals(msg)) {
- /* 接收退出命令时,处理退出 */
- DataOutputStream out = new DataOutputStream(
- client.getOutputStream());
- out.writeUTF(EXIT_COMMAND); // 再返回至客户端,使得退出循环
- out.flush();
- if (null != listener) {
- listener.onExited(client.getInetAddress());
- }
- break;
- } else {
- /* 否则,处理接收消息*/
- if (null != listener) {
- listener.onReceive(client.getInetAddress(), msg);
- }
- }
- /* 回复或转发已接收数据 */
- }
- } catch (SocketException e) { // Connection reset
- if (null != listener) {
- listener.onSocketException(client.getInetAddress());
- }
- } catch (IOException e) {
- e.printStackTrace();
- } finally {
- mClientList.remove(client); // 移除当前客户端
- try {
- if (null != in) {
- in.close();
- }
- if (null != client) {
- client.close();
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- }
- /** 向客户端群发信息 */
- public void sendMessage(String msg) {
- int i = 0;
- try {
- DataOutputStream out = null;
- for (; i < mClientList.size(); i++) {
- out = new DataOutputStream(mClientList.get(i).getOutputStream());
- out.writeUTF(msg);
- out.flush();
- }
- } catch (SocketException e) { // Connection reset
- if (null != listener && mClientList.size() > 0) {
- listener.onSocketException(mClientList.get(i).getInetAddress());
- }
- mClientList.remove(i); // 移除出异常的那个客户端
- } catch (IOException e) {
- e.printStackTrace();
- mClientList.remove(i); // 移除出异常的那个客户端
- }
- }
- /** 设置服务器监听接口 */
- public void setOnServerListener(OnServerListener listener) {
- this.listener = listener;
- }
- }
1.2)EasyClient.java
- /**
- * 接收和发送消息的客户端
- *
- * @author Join
- */
- public class EasyClient extends Thread {
- (还报8W字符冗余,受不住了,就这么着吧T^T)...
- }
1.3)JsonUtil.java
- public class JsonUtil {
- /**
- * 解析Object成为json
- *
- * @param obj 对象
- * @return json字符串
- */
- public static String objToJson(Object obj) {
- JSONStringer arrayJson = new JSONStringer(); // Json构造对象
- Class<?> clazz = obj.getClass(); // 获取对象运行时类
- try {
- arrayJson.array().value(clazz.getName()); // 创建数组,第一位存放类名
- JSONStringer objJson = new JSONStringer(); // Json构造对象
- objJson.object();
- Field[] fields = clazz.getDeclaredFields(); // 返回类声明的所有字段
- for (Field field : fields) {
- field.setAccessible(true); // 设置变量可访问
- objJson.key(field.getName()).value(field.get(obj));
- }
- objJson.endObject();
- arrayJson.value(objJson).endArray(); // 第二位存放类对象
- } catch (IllegalArgumentException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- } catch (JSONException e) {
- e.printStackTrace();
- }
- return arrayJson.toString();
- }
- /**
- * 解析json成为Object
- *
- * @param json json字符串
- * @return 对象
- * @warning 由于是使用newInstance()构建实例,自己写构造函数时要显式写明默认构造函数
- */
- public static Object jsonToObj(String json) {
- Object obj = null;
- try {
- JSONArray jarray = new JSONArray(json);
- String className = jarray.getString(0); // 获得第一位类名
- Class<?> clazz = Class.forName(className); // 载入该类
- obj = clazz.newInstance(); // 构建实例
- JSONObject jobj = new JSONObject(jarray.getString(1)); // 获得第二位类对象
- @SuppressWarnings("unchecked")
- Iterator<String> it = jobj.keys();
- Field field;
- while (it.hasNext()) {
- String key = it.next();
- field = clazz.getDeclaredField(key);
- setValue(obj, field, jobj.getString(key));
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- return obj;
- }
- /**
- * 给字段设值
- *
- * @param obj 对象
- * @param field 字段
- * @param value 值
- */
- private static void setValue(Object obj, Field field, String value)
- throws IllegalArgumentException, IllegalAccessException {
- ...
- }
- }
本文转自winorlose2000 51CTO博客,原文链接:http://blog.51cto.com/vaero/893886,如需转载请自行联系原作者