<a target="_blank" href="http://vaero.blog.51cto.com/4350852/893886">Android實時繪制效果(一)</a>
<b>2</b><b>)繪制部分</b>
修改的ApiDemos的FingerPaint例子。有ClientView和ServerView,而父類BaseView放置共用的東西,也保證繪制效果一緻。
2.1)BaseView.java<b></b>
public class BaseView extends View {
protected OnExitedListener listener;
public interface OnExitedListener {
void onExited(View v);
}
protected Paint mPaint;
protected Bitmap mBitmap;
protected Canvas mCanvas;
protected Path mPath;
protected Paint mBitmapPaint;
protected static final String KEY_INFO = "info";
protected final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
String info = msg.getData().getString(KEY_INFO);
Toast.makeText(getContext(), info, Toast.LENGTH_SHORT).show();
}
};
public BaseView(Context context, int width, int height) {
super(context);
mPaint = new Paint(); // 建立線條畫筆
mPaint.setAntiAlias(true); // 設定抗鋸齒
mPaint.setDither(true); // 設定遞色
mPaint.setColor(0xFFFF0000); // 設定畫筆顔色
mPaint.setStyle(Paint.Style.STROKE); // 設定畫筆類型
mPaint.setStrokeJoin(Paint.Join.ROUND); // 預設MITER
mPaint.setStrokeCap(Paint.Cap.ROUND); // 預設BUTT
mPaint.setStrokeWidth(12); // 設定描邊寬度
mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); // 建立bitmap對象
mCanvas = new Canvas(mBitmap); // 嵌入Canvas
mPath = new Path(); // 建立畫筆路徑
mBitmapPaint = new Paint(Paint.DITHER_FLAG); // 建立圖像畫筆
/* 設定獲得焦點,以觸發onKeyDown */
requestFocus();
setFocusableInTouchMode(true);
protected void toastMessage(String info) {
Message msg = mHandler.obtainMessage();
Bundle data = new Bundle();
data.putString(KEY_INFO, info);
msg.setData(data);
mHandler.sendMessage(msg);
public void onBackPressed() {
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
onBackPressed();
return super.onKeyDown(keyCode, event);
public void setOnExitedListener(OnExitedListener listener) {
this.listener = listener;
}
2.2)ClientView.java<b></b>
public class ClientView extends BaseView implements OnClientListener {
private EasyClient mEasyClient;
private boolean hasStart = false;
private Display mDisplay;
private float wRatio = 1f, hRatio = 1f; // 螢幕縮放比
private Runnable mRunnable = new Runnable() {
public void run() {
Toast.makeText(getContext(), "已過5秒,網絡不通暢?", Toast.LENGTH_LONG)
.show();
public ClientView(Context context, String host, int port, Display display) {
super(context, display.getWidth(), display.getHeight());
mDisplay = display;
mEasyClient = new EasyClient(host, port, 10000);
mEasyClient.setOnClientListener(this);
mEasyClient.start();
mHandler.postDelayed(mRunnable, 5000);
mEasyClient.sendMessage(EasyServer.EXIT_COMMAND);
protected void onDraw(Canvas canvas) {
canvas.drawColor(0xFFAAAAAA);
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
private float mX, mY;
private void touch_start(float x, float y) {
hasStart = true;
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
private void touch_move(float x, float y) {
if (hasStart) {
mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
mX = x;
mY = y;
} else {
touch_start(x, y);
private void touch_up(float x, float y) {
hasStart = false;
// mPath.lineTo(mX, mY);
mPath.lineTo(x, y);
// commit the path to our offscreen
mCanvas.drawPath(mPath, mPaint);
// kill this so we don't double draw
public void onConnectException() {
mHandler.removeCallbacks(mRunnable);
toastMessage("連接配接不到伺服器!");
if (null != listener) {
listener.onExited(this);
public void onTimeoutException() {
toastMessage("連接配接伺服器逾時!");
public void onSocketException() {
toastMessage("通信異常!");
public void onConnected() {
toastMessage("連接配接上了伺服器!");
public void onReceive(String msg) {
Object obj = JsonUtil.jsonToObj(msg);
if (obj instanceof ScreenInfo) {
ScreenInfo info = (ScreenInfo) obj;
wRatio = ((float) mDisplay.getWidth()) / info.getWidth();
hRatio = ((float) mDisplay.getHeight()) / info.getHeight();
} else if (obj instanceof PonitInfo) {
PonitInfo info = (PonitInfo) obj;
float x = wRatio * info.getX();
float y = hRatio * info.getY();
switch (info.getState()) {
case 0:
touch_start(x, y);
postInvalidate();
break;
case 1:
touch_move(x, y);
case 2:
touch_up(x, y);
}
public void onExited() {
toastMessage("用戶端退出了!");
2.3)ServerView.java<b></b>
public class ServerView extends BaseView implements OnServerListener {
private EasyServer mEasyServer;
public ServerView(Context context, int port, Display display) {
/* 開啟服務 */
mEasyServer = new EasyServer(port);
mEasyServer.setOnServerListener(this);
mEasyServer.start();
mEasyServer.sendMessage(EasyServer.EXIT_COMMAND);
/* 傳回至前頁面時,端口仍被占用。可以在這裡殺死相關程序,以避免端口占用。 */
private static final float TOUCH_TOLERANCE = 4;
mEasyServer.sendMessage(JsonUtil.objToJson(new PonitInfo(x, y, 0)));
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
mEasyServer.sendMessage(JsonUtil.objToJson(new PonitInfo(x, y, 1)));
private void touch_up() {
mEasyServer.sendMessage(JsonUtil.objToJson(new PonitInfo(mX, mY, 2)));
mPath.lineTo(mX, mY);
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
case MotionEvent.ACTION_UP:
touch_up();
return true;
public void onBindException() {
toastMessage("端口占用了,請關閉應用後重開!");
public void onSocketException(InetAddress ip) {
toastMessage(ip + "異常退出!");
public void onClientConnected(InetAddress ip) {
toastMessage(ip + "建立了連接配接!");
/* 發送ScreenInfo資訊 */
mEasyServer.sendMessage(JsonUtil.objToJson(new ScreenInfo(mDisplay
.getWidth(), mDisplay.getHeight())));
public void onReceive(InetAddress ip, String msg) {
/* 接收用戶端消息 */
public void onExited(InetAddress ip) {
toastMessage(ip + "正常退出!");
<b>四、後記</b>
1、NIO Socket通信還不是很熟悉,是以還是Socket了。至于多線程和NIO效率在各情況下孰優孰劣不清楚。而長連接配接是為了實時。
2、用戶端連接配接以Socket集合來記錄,在n多時會有什麼什麼。算了,現Demo不面臨這種風險~
3、現在的通信消息太複雜了,沒必要這樣的。
可以多拿幾個裝置測試玩玩^^
<a href="http://down.51cto.com/data/2360760" target="_blank">附件:http://down.51cto.com/data/2360760</a>
本文轉自winorlose2000 51CTO部落格,原文連結:http://blog.51cto.com/vaero/893887,如需轉載請自行聯系原作者