天天看點

Android實時繪制效果(二)

<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 &amp;&amp; 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 &gt;= TOUCH_TOLERANCE || dy &gt;= 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,如需轉載請自行聯系原作者

繼續閱讀