Android实时绘制效果(一)

 
2 )绘制部分
         修改的ApiDemos的FingerPaint例子。有ClientView和ServerView,而父类BaseView放置共用的东西,也保证绘制效果一致。
 
2.1)BaseView.java
 
  
  1. public class BaseView extends View { 
  2.  
  3.     protected OnExitedListener listener; 
  4.  
  5.     public interface OnExitedListener { 
  6.         void onExited(View v); 
  7.     } 
  8.  
  9.     protected Paint mPaint; 
  10.     protected Bitmap mBitmap; 
  11.     protected Canvas mCanvas; 
  12.     protected Path mPath; 
  13.     protected Paint mBitmapPaint; 
  14.  
  15.     protected static final String KEY_INFO = "info"
  16.     protected final Handler mHandler = new Handler() { 
  17.         @Override 
  18.         public void handleMessage(Message msg) { 
  19.             String info = msg.getData().getString(KEY_INFO); 
  20.             Toast.makeText(getContext(), info, Toast.LENGTH_SHORT).show(); 
  21.         } 
  22.     }; 
  23.  
  24.     public BaseView(Context context, int width, int height) { 
  25.         super(context); 
  26.  
  27.         mPaint = new Paint(); // 创建线条画笔 
  28.         mPaint.setAntiAlias(true); // 设置抗锯齿 
  29.         mPaint.setDither(true); // 设置递色 
  30.         mPaint.setColor(0xFFFF0000); // 设置画笔颜色 
  31.         mPaint.setStyle(Paint.Style.STROKE); // 设置画笔类型 
  32.         mPaint.setStrokeJoin(Paint.Join.ROUND); // 默认MITER 
  33.         mPaint.setStrokeCap(Paint.Cap.ROUND); // 默认BUTT 
  34.         mPaint.setStrokeWidth(12); // 设置描边宽度 
  35.  
  36.         mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); // 创建bitmap对象 
  37.         mCanvas = new Canvas(mBitmap); // 嵌入Canvas 
  38.         mPath = new Path(); // 创建画笔路径 
  39.         mBitmapPaint = new Paint(Paint.DITHER_FLAG); // 创建图像画笔 
  40.  
  41.         /* 设置获得焦点,以触发onKeyDown */ 
  42.         requestFocus(); 
  43.         setFocusableInTouchMode(true); 
  44.     } 
  45.  
  46.     protected void toastMessage(String info) { 
  47.         Message msg = mHandler.obtainMessage(); 
  48.         Bundle data = new Bundle(); 
  49.         data.putString(KEY_INFO, info); 
  50.         msg.setData(data); 
  51.         mHandler.sendMessage(msg); 
  52.     } 
  53.  
  54.     public void onBackPressed() { 
  55.     } 
  56.  
  57.     @Override 
  58.     public boolean onKeyDown(int keyCode, KeyEvent event) { 
  59.         if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) { 
  60.             onBackPressed(); 
  61.         } 
  62.         return super.onKeyDown(keyCode, event); 
  63.     } 
  64.  
  65.     public void setOnExitedListener(OnExitedListener listener) { 
  66.         this.listener = listener; 
  67.     } 
  68.  
 
2.2)ClientView.java
 
  
  1. public class ClientView extends BaseView implements OnClientListener { 
  2.  
  3.     private EasyClient mEasyClient; 
  4.     private boolean hasStart = false
  5.     private Display mDisplay; 
  6.     private float wRatio = 1f, hRatio = 1f; // 屏幕缩放比 
  7.  
  8.     private Runnable mRunnable = new Runnable() { 
  9.         @Override 
  10.         public void run() { 
  11.             Toast.makeText(getContext(), "已过5秒,网络不通畅?", Toast.LENGTH_LONG) 
  12.                     .show(); 
  13.         } 
  14.     }; 
  15.  
  16.     public ClientView(Context context, String host, int port, Display display) { 
  17.         super(context, display.getWidth(), display.getHeight()); 
  18.         mDisplay = display; 
  19.  
  20.         mEasyClient = new EasyClient(host, port, 10000); 
  21.         mEasyClient.setOnClientListener(this); 
  22.         mEasyClient.start(); 
  23.  
  24.         mHandler.postDelayed(mRunnable, 5000); 
  25.     } 
  26.  
  27.     @Override 
  28.     public void onBackPressed() { 
  29.         mEasyClient.sendMessage(EasyServer.EXIT_COMMAND); 
  30.     } 
  31.  
  32.     @Override 
  33.     protected void onDraw(Canvas canvas) { 
  34.         canvas.drawColor(0xFFAAAAAA); 
  35.         canvas.drawBitmap(mBitmap, 00, mBitmapPaint); 
  36.         canvas.drawPath(mPath, mPaint); 
  37.     } 
  38.  
  39.     private float mX, mY; 
  40.  
  41.     private void touch_start(float x, float y) { 
  42.         hasStart = true
  43.         mPath.reset(); 
  44.         mPath.moveTo(x, y); 
  45.         mX = x; 
  46.         mY = y; 
  47.     } 
  48.  
  49.     private void touch_move(float x, float y) { 
  50.         if (hasStart) { 
  51.             mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2); 
  52.             mX = x; 
  53.             mY = y; 
  54.         } else { 
  55.             touch_start(x, y); 
  56.         } 
  57.     } 
  58.  
  59.     private void touch_up(float x, float y) { 
  60.         hasStart = false
  61.         // mPath.lineTo(mX, mY); 
  62.         mPath.lineTo(x, y); 
  63.         // commit the path to our offscreen 
  64.         mCanvas.drawPath(mPath, mPaint); 
  65.         // kill this so we don't double draw 
  66.         mPath.reset(); 
  67.     } 
  68.  
  69.     @Override 
  70.     public void onConnectException() { 
  71.         mHandler.removeCallbacks(mRunnable); 
  72.         toastMessage("连接不到服务器!"); 
  73.         if (null != listener) { 
  74.             listener.onExited(this); 
  75.         } 
  76.     } 
  77.  
  78.     @Override 
  79.     public void onTimeoutException() { 
  80.         mHandler.removeCallbacks(mRunnable); 
  81.         toastMessage("连接服务器超时!"); 
  82.         if (null != listener) { 
  83.             listener.onExited(this); 
  84.         } 
  85.     } 
  86.  
  87.     @Override 
  88.     public void onSocketException() { 
  89.         mHandler.removeCallbacks(mRunnable); 
  90.         toastMessage("通信异常!"); 
  91.         if (null != listener) { 
  92.             listener.onExited(this); 
  93.         } 
  94.     } 
  95.  
  96.     @Override 
  97.     public void onConnected() { 
  98.         mHandler.removeCallbacks(mRunnable); 
  99.         toastMessage("连接上了服务器!"); 
  100.     } 
  101.  
  102.     @Override 
  103.     public void onReceive(String msg) { 
  104.         Object obj = JsonUtil.jsonToObj(msg); 
  105.         if (obj instanceof ScreenInfo) { 
  106.             ScreenInfo info = (ScreenInfo) obj; 
  107.             wRatio = ((float) mDisplay.getWidth()) / info.getWidth(); 
  108.             hRatio = ((float) mDisplay.getHeight()) / info.getHeight(); 
  109.         } else if (obj instanceof PonitInfo) { 
  110.             PonitInfo info = (PonitInfo) obj; 
  111.             float x = wRatio * info.getX(); 
  112.             float y = hRatio * info.getY(); 
  113.             switch (info.getState()) { 
  114.             case 0
  115.                 touch_start(x, y); 
  116.                 postInvalidate(); 
  117.                 break
  118.             case 1
  119.                 touch_move(x, y); 
  120.                 postInvalidate(); 
  121.                 break
  122.             case 2
  123.                 touch_up(x, y); 
  124.                 postInvalidate(); 
  125.                 break
  126.             } 
  127.         } 
  128.     } 
  129.  
  130.     @Override 
  131.     public void onExited() { 
  132.         toastMessage("客户端退出了!"); 
  133.         if (null != listener) { 
  134.             listener.onExited(this); 
  135.         } 
  136.     } 
  137.  
 
2.3)ServerView.java
 
  
  1. public class ServerView extends BaseView implements OnServerListener { 
  2.  
  3.     private EasyServer mEasyServer; 
  4.     private Display mDisplay; 
  5.  
  6.     public ServerView(Context context, int port, Display display) { 
  7.         super(context, display.getWidth(), display.getHeight()); 
  8.         mDisplay = display; 
  9.  
  10.         /* 开启服务 */ 
  11.         mEasyServer = new EasyServer(port); 
  12.         mEasyServer.setOnServerListener(this); 
  13.         mEasyServer.start(); 
  14.     } 
  15.  
  16.     @Override 
  17.     public void onBackPressed() { 
  18.         mEasyServer.sendMessage(EasyServer.EXIT_COMMAND); 
  19.         /* 返回至前页面时,端口仍被占用。可以在这里杀死相关进程,以避免端口占用。 */ 
  20.         if (null != listener) { 
  21.             listener.onExited(this); 
  22.         } 
  23.     } 
  24.  
  25.     @Override 
  26.     protected void onDraw(Canvas canvas) { 
  27.         canvas.drawColor(0xFFAAAAAA); 
  28.         canvas.drawBitmap(mBitmap, 00, mBitmapPaint); 
  29.         canvas.drawPath(mPath, mPaint); 
  30.     } 
  31.  
  32.     private float mX, mY; 
  33.     private static final float TOUCH_TOLERANCE = 4
  34.  
  35.     private void touch_start(float x, float y) { 
  36.  
  37.         mEasyServer.sendMessage(JsonUtil.objToJson(new PonitInfo(x, y, 0))); 
  38.  
  39.         mPath.reset(); 
  40.         mPath.moveTo(x, y); 
  41.         mX = x; 
  42.         mY = y; 
  43.     } 
  44.  
  45.     private void touch_move(float x, float y) { 
  46.         float dx = Math.abs(x - mX); 
  47.         float dy = Math.abs(y - mY); 
  48.         if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) { 
  49.  
  50.             mEasyServer.sendMessage(JsonUtil.objToJson(new PonitInfo(x, y, 1))); 
  51.  
  52.             mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2); 
  53.             mX = x; 
  54.             mY = y; 
  55.         } 
  56.     } 
  57.  
  58.     private void touch_up() { 
  59.  
  60.         mEasyServer.sendMessage(JsonUtil.objToJson(new PonitInfo(mX, mY, 2))); 
  61.  
  62.         mPath.lineTo(mX, mY); 
  63.         // commit the path to our offscreen 
  64.         mCanvas.drawPath(mPath, mPaint); 
  65.         // kill this so we don't double draw 
  66.         mPath.reset(); 
  67.     } 
  68.  
  69.     @Override 
  70.     public boolean onTouchEvent(MotionEvent event) { 
  71.         float x = event.getX(); 
  72.         float y = event.getY(); 
  73.  
  74.         switch (event.getAction()) { 
  75.         case MotionEvent.ACTION_DOWN: 
  76.             touch_start(x, y); 
  77.             invalidate(); 
  78.             break
  79.         case MotionEvent.ACTION_MOVE: 
  80.             touch_move(x, y); 
  81.             invalidate(); 
  82.             break
  83.         case MotionEvent.ACTION_UP: 
  84.             touch_up(); 
  85.             invalidate(); 
  86.             break
  87.         } 
  88.         return true
  89.     } 
  90.  
  91.     @Override 
  92.     public void onBindException() { 
  93.         toastMessage("端口占用了,请关闭应用后重开!"); 
  94.     } 
  95.  
  96.     @Override 
  97.     public void onSocketException(InetAddress ip) { 
  98.         toastMessage(ip + "异常退出!"); 
  99.     } 
  100.  
  101.     @Override 
  102.     public void onClientConnected(InetAddress ip) { 
  103.         toastMessage(ip + "建立了连接!"); 
  104.         /* 发送ScreenInfo信息 */ 
  105.         mEasyServer.sendMessage(JsonUtil.objToJson(new ScreenInfo(mDisplay 
  106.                 .getWidth(), mDisplay.getHeight()))); 
  107.     } 
  108.  
  109.     @Override 
  110.     public void onReceive(InetAddress ip, String msg) { 
  111.         /* 接收客户端消息 */ 
  112.     } 
  113.  
  114.     @Override 
  115.     public void onExited(InetAddress ip) { 
  116.         toastMessage(ip + "正常退出!"); 
  117.     } 
  118.  
 
四、后记
         1、NIO Socket通信还不是很熟悉,所以还是Socket了。至于多线程和NIO效率在各情况下孰优孰劣不清楚。而长连接是为了实时。
         2、客户端连接以Socket集合来记录,在n多时会有什么什么。算了,现Demo不面临这种风险~
         3、现在的通信消息太复杂了,没必要这样的。
 
         可以多拿几个设备测试玩玩^^