1. 程式人生 > >你畫我猜核心功能實現 Android客戶端+Java服務端

你畫我猜核心功能實現 Android客戶端+Java服務端

     本篇文章是我以前寫的一篇文章的改版,上一篇文章已刪除,因為以前的部落格有的朋友說執行不起來,我現在想起來所以重新修改了以下程式碼,因為我這測試機就兩個,只能測試一個繪製者和一個觀看者。

下面上程式碼,首先是我們的Android客戶端-------------------

Android實現原理就是自定義View,然後繼承的是SurfaceView,不繼承View的原因就是SurfaceView這個視圖裡內嵌了一個專門用於繪製的Surface。

先看一下我們自定義的DrawGameView,也就是繼承自SurfaceView的一個View。

public class DrawGameView extends 
SurfaceView implements SurfaceHolder.Callback { private SurfaceHolder holder; private SurfaceThread thread; WindowManager wm = (WindowManager) getContext() .getSystemService(Context.WINDOW_SERVICE); int screenW = wm.getDefaultDisplay().getWidth(); int screenH = wm.getDefaultDisplay().getHeight();
// private Canvas canvas; public SurfaceThread getThread() { return thread; } public DrawGameView(Context context) { super(context); init(); } public DrawGameView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public void init() { holder
= getHolder(); holder.addCallback(this); } @Override public void surfaceCreated(SurfaceHolder holder) { thread = new SurfaceThread(); thread.start(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { } public class SurfaceThread extends Thread { private Path path; private Paint paint; private ArrayList<DrawStep> steps = new ArrayList<DrawStep>(); private ArrayList<Path> paths = new ArrayList<Path>(); public SurfaceThread() { path = new Path(); paint = new Paint(); paint.setAntiAlias(true); paint.setColor(Color.BLUE); paint.setStrokeWidth(5); paint.setStyle(Paint.Style.STROKE); } @Override public void run() { super.run(); while (true) { draw(); try { Thread.sleep(17); } catch (InterruptedException e) { e.printStackTrace(); } } } public void addStep(DrawStep step) { steps.add(step); } public void draw() { Canvas canvas = null; try { canvas = holder.lockCanvas();//鎖整個畫布 if (canvas != null) { while (steps.size() > 0) { DrawStep step = steps.remove(0); if (step.getType() == DrawStep.MoveTo) { path.moveTo(screenW * ((float) step.getxP() / 10000), screenH * ((float) step.getyP() / 10000)); } else if (step.getType() == DrawStep.LineTo) { path.lineTo(screenW * ((float) step.getxP() / 10000), screenH * ((float) step.getyP() / 10000)); } else if (step.getType() == DrawStep.UP) { Path path1 = new Path(path); paths.add(path1); } } for (int i = 0; i < paths.size(); i++) { canvas.drawPath(paths.get(i), paint); } canvas.drawPath(path, paint); holder.unlockCanvasAndPost(canvas); } } catch (Exception e) { } } } }

我先把所有程式碼貼上吧,沒什麼東西,如果有問題可以給我發私信。

MainActivity程式碼

public class MainActivity extends Activity {
    private static DrawGameView drawGameView;
DisplayMetrics dm = new DisplayMetrics();
    int screenW;
    int screenH;
@SuppressLint("ClickableViewAccessibility")
    @Override
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
NetWorkMessage.get_Instance().setActivity(this);
drawGameView = new DrawGameView(this);
setContentView(drawGameView);
getWindowManager().getDefaultDisplay().getMetrics(dm);
screenW = dm.widthPixels;
screenH = dm.heightPixels;
drawGameView.setOnTouchListener(new View.OnTouchListener() {
            @Override
public boolean onTouch(View v, MotionEvent event) {
                if (NetWorkMessage.get_Instance().isDrawer()) {
//                if (true) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
                        case MotionEvent.ACTION_DOWN:
                            addStep(DrawStep.MoveTo, (int) (event.getX() / screenW * 10000), (int) (event.getY() / screenH * 10000));
                            break;
                        case MotionEvent.ACTION_MOVE:
                            addStep(DrawStep.LineTo, (int) (event.getX() / screenW * 10000), (int) (event.getY() / screenH * 10000));
                            break;
                        case MotionEvent.ACTION_UP:
                            addStep(DrawStep.UP, 0, 0);
                            break;
}
                    return true;
} else {
                    return false;
}
            }
        });
}

    public void addStep(byte type, int xp, int yp) {
        DrawStep step = new DrawStep();
step.setType(type);
step.setxP(xp);
step.setyP(yp);
NetWorkMessage.get_Instance().sendDrawMsgToServer(step);
addOneStep(step);
}

    public void addOneStep(DrawStep step) {
        drawGameView.getThread().addStep(step);
}


//    public static void drawStep(DrawStep drawStep) {
//        drawGameView.postInvalidate();
////        drawView.forceLayout();
//    }
}

GameApplication在這裡做了Socket的初始化

public class GameApplication extends Application {
    @Override
public void onCreate() {
        super.onCreate();
NetWorkMessage.get_Instance().createNetWork();
//        NetWorkMessage.get_instaance().receiveLoginNetWork();
NetWorkMessage.get_Instance().receiveDrawNetWork();
}
}

Command定義的伺服器與客戶端互動的命令

public class Command {
    public static final byte LOGIN = 1;
    public static final byte DRAW = 2;
    public static final byte LOGIN_OUT = 3;//登出
}

NetWorkMessage主要是處理Socket連線、接收和傳送資料的

public class NetWorkMessage {
    private final String TAG = "NetWorkMessage";
    private Socket socket = new Socket();
    private static NetWorkMessage _instance = new NetWorkMessage();
    public boolean isDraw;
    private MainActivity activity;
    public MainActivity getActivity() {
        return activity;
}

    public void setActivity(MainActivity activity) {
        this.activity = activity;
}

    public static NetWorkMessage get_Instance() {
        return _instance;
}


    public void sendDrawMsgToServer(DrawStep drawStep) {
        try {
            //傳送內容
DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream());
            int len = 10;
ByteArray data = new ByteArray();
data.writeInt(len);
data.writeByte(Command.DRAW);
data.writeByte(drawStep.getType());
data.writeInt(drawStep.getxP());
data.writeInt(drawStep.getyP());
outputStream.write(data.toByteArray());
outputStream.flush();
} catch (Exception e) {
            e.printStackTrace();
Log.d(TAG, "沒有傳送成功======客戶端----斷開連線");
}
    }

    public void createNetWork() {
        new Thread(createNetwork).start();
}

    public void receiveDrawNetWork() {
        new Thread(receiveDrawNetwork).start();
}

    private Runnable createNetwork = new Runnable() {
        @Override
public void run() {
            try {
//                socket = new Socket("192.168.0.102", 8888);
socket = new Socket("192.168.1.105", 8888);
requestLogin();
} catch (IOException e) {
                e.printStackTrace();
}
        }
    };
/**
     * 請求登入
     */
private void requestLogin()
    {
        try{
            DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream());
String userKey = (String) SharedPreferencesUtil.getData(getActivity(), Configs.LOCAL_USER_KEY, "");
            int len = 5 + userKey.length();
ByteArray data = new ByteArray();
data.writeInt(len);
data.writeByte(Command.LOGIN);
data.writeByteArray(userKey.getBytes());
outputStream.write(data.toByteArray());
outputStream.flush();
}catch (Exception e)
        {

        }
    }


    private Runnable receiveDrawNetwork = new Runnable() {
        @Override
public void run() {
            while (true) {
                receiveDraw();
}
        }
    };
    private void receiveDraw() {
        //接收伺服器返回資訊
try {
            DataInputStream inputStream = new DataInputStream(socket.getInputStream());
            if (inputStream.available() != 0) {
                int len = inputStream.readInt();
                byte[] buffer = new byte[len];
inputStream.read(buffer, 0, len);
ByteArray data = new ByteArray(buffer);
                byte cmd = data.readByte();
                if (cmd == Command.LOGIN) {
                    Log.d(TAG, "-----------BEGIN-----------------");
                    byte[] userKeyByteArr = data.readByteArray(5, 36);
Log.d(TAG, "-----------EDN-----------------");
String userKey = new String(userKeyByteArr);
                    if (userKey != null && !"".equals(userKey))
                    {
                        SharedPreferencesUtil.saveData(getActivity(), Configs.LOCAL_USER_KEY, userKey);
}
                    Log.d(TAG, "userKey=============" + userKey);
//12e0962f-3789-48a5-9b9e-74a256544949
int tag = data.readInt();
Log.d(TAG, "tag=============" + tag);
                    if (tag == 1) {
                        setDrawer(true);
} else {
                        setDrawer(false);
}
                } else if (cmd == Command.DRAW) {
                    byte type = data.readByte();
                    int x = data.readInt();
                    int y = data.readInt();
DrawStep drawStep = new DrawStep();
drawStep.setxP(x);
drawStep.setyP(y);
drawStep.setType(type);
activity.addOneStep(drawStep);
}
//                MainActivity.drawStep(msg);
}
        } catch (Exception e) {
            e.printStackTrace();
}
    }


    public boolean isDrawer() {
        return isDraw;
}

    public void setDrawer(boolean draw) {
        isDraw = draw;
}


}

DrawSept,繪製的時候前後臺互動傳輸的資料格式

public class DrawStep {
    public static final byte MoveTo = 1;
    public static final byte LineTo = 2;
    public static final byte UP = 3;
    private byte type;
    private int xP;
    private int yP;
    public byte getType() {
        return type;
}

    public void setType(byte type) {
        this.type = type;
}

    public int getxP() {
        return xP;
}

    public void setxP(int xP) {
        this.xP = xP;
}

    public int getyP() {
        return yP;
}

    public void setyP(int yP) {
        this.yP = yP;
}
}

SharePreferencesUtil 本地儲存工具類,用來儲存伺服器返回的userKey

public class SharedPreferencesUtil {
    //儲存的sharedpreferences檔名
private static final String FILE_NAME = "save_file_name";
/**
     * 儲存資料到檔案
     *
     * @param context
* @param key
* @param data
*/
public static void saveData(Context context, String key, Object data){

        String type = data.getClass().getSimpleName();
SharedPreferences sharedPreferences = context
                .getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
        if ("Integer".equals(type)){
            editor.putInt(key, (Integer)data);
}else if ("Boolean".equals(type)){
            editor.putBoolean(key, (Boolean)data);
}else if ("String".equals(type)){
            editor.putString(key, (String)data);
}else if ("Float".equals(type)){
            editor.putFloat(key, (Float)data);
}else if ("Long".equals(type)){
            editor.putLong(key, (Long)data);
}

        editor.commit();
}

    /**
     * 清除本地儲存的資料
     *
     * @param context
* @param key
*/
public static void removeData(Context context, String key)
    {
        SharedPreferences sharedPreferences = context
                .getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.remove(key);
editor.commit();
}

    /**
     * 從檔案中讀取資料
     * @param context
* @param key
* @param defValue
* @return
*/
public static Object getData(Context context, String key, Object defValue){

        String type = defValue.getClass().getSimpleName();
SharedPreferences sharedPreferences = context.getSharedPreferences (FILE_NAME, Context.MODE_PRIVATE);
//defValue為為預設值,如果當前獲取不到資料就返回它
if ("Integer".equals(type)){
            return sharedPreferences.getInt(key, (Integer)defValue);
}else if ("Boolean".equals(type)){
            return sharedPreferences.getBoolean(key, (Boolean)defValue);
}else if ("String".equals(type)){
            return sharedPreferences.getString(key, (String)defValue);
}else if ("Float".equals(type)){
            return sharedPreferences.getFloat(key, (Float)defValue);
}else if ("Long".equals(type)){
            return sharedPreferences.getLong(key, (Long)defValue);
}

        return null;
}
}

ByteArray

public class ByteArray {
    /**
     * DEFAULT_SIZE
     */
private static final byte DEFAULT_SIZE = 16;
/**
     * BOOLEAN_SIZE
     */
static final public byte BOOLEAN_SIZE = 1;
/**
     * BYTE_SIZE
     */
static final public byte BYTE_SIZE = 1;
/**
     * CHAR_SIZE
     */
static final public byte CHAR_SIZE = 2;
/**
     * SHORT_SIZE
     */
static final public byte SHORT_SIZE = 2;
/**
     * INT_SIZE
     */
static final public byte INT_SIZE = 4;
/**
     * LONG_SIZE
     */
static final public byte LONG_SIZE = 8;
/**
     * 當前位置
     */
private int currentPos = 0;
/**
     * byte陣列資料
     */
private byte[] data;
/**
     * 預設大小構造
     */
public ByteArray() {
        this(DEFAULT_SIZE);
}

    /**
     * 指定大小構造
     *
     * @param size 指定的大小
     */
public ByteArray(int size) {
        data = new byte[size];
currentPos = 0;
}

    /**
     * 指定資料構造
     *
     * @param src 指定的資料來源
     */
public ByteArray(byte[] src) {
        data = src;
currentPos = 0;
}

    /**
     * writeBoolean
     *
     * @param val
*/
public void writeBoolean(boolean val) {
        ensureCapacity(BOOLEAN_SIZE);
data[currentPos++] = (byte) (val ? 1 : 0);
}

    /**
     * writeByte
     *
     * @param val
*/
public void writeByte(byte val) {
        ensureCapacity(BYTE_SIZE);
data[currentPos++] = val;
}

    /**
     * writeByte
     *
     * @param val
*/
public void writeByte(int val) {
        writeByte((byte) val);
}

    /**
     * writeChar
     *
     * @param c
*/
public void writeChar(char c) {
        ensureCapacity(CHAR_SIZE);
data[currentPos + 1] = (byte) (c >>> 0);
data[currentPos + 0] = (byte) (c >>> 8);
currentPos += 2;
}

    /**
     * writeShort
     *
     * @param val
*/
public void writeShort(short val) {
        ensureCapacity(SHORT_SIZE);
data[currentPos + 1] = (byte) (val >>> 0);
data[currentPos + 0] = (byte) (val >>> 8);
currentPos += 2;
}

    /**
     * writeShort
     *
     * @param val
*/
public void writeShort(int val) {
        writeShort((short) val);
}

    /**
     * writeInt
     *
     * @param val
*/
public void writeInt(int val) {
        ensureCapacity(INT_SIZE);
data[currentPos + 3] = (byte) (val >>> 0);
data[currentPos + 2] = (byte) (val >>> 8);
data[currentPos + 1] = (byte) (val >>> 16);
data[currentPos + 0] = (byte) (val >>> 24);
currentPos += INT_SIZE;
}

    /**
     * writeLong
     *
     * @param val
*/
public void writeLong(long val) {
        ensureCapacity(LONG_SIZE);
data[currentPos + 7] = (byte) (val >>> 0);
data[currentPos + 6] = (byte) (val >>> 8);
data[currentPos + 5] = (byte) (val >>> 16);
data[currentPos + 4] = (byte) (val >>> 24);
data[currentPos + 3] = (byte) (val >>> 32);
data[currentPos + 2] = (byte) (val >>> 40);
data[currentPos + 1] = (byte) (val >>> 48);
data[currentPos + 0] = (byte) (val >>> 56);
currentPos += LONG_SIZE;
}

    /**
     * writeByteArray
     *

            
           

相關推薦

核心功能實現 Android客戶+Java服務

     本篇文章是我以前寫的一篇文章的改版,上一篇文章已刪除,因為以前的部落格有的朋友說執行不起來,我現在想起來所以重新修改了以下程式碼,因為我這測試機就兩個,只能測試一個繪製者和一個觀看者。下面上程式碼,首先是我們的Android客戶端------------------

使用websocket實現

1,環境配置(nodejs) 檔案結構: package.json: { "name": "websocket", "version": "1.0.0", "description": "", "main": "index.js", "scrip

題目庫

之前在電腦上玩過線上的你畫我猜,感覺很有意思。正好我們部門迭代會之後都會玩個小遊戲,於是我組織了一個線下的你畫大家猜,效果還不錯。 由於線下不同線上的特點我對規則重新制定了一下,規則可以是靈活多變的,大家都認同玩的開心就好。 再下面就是遊戲的題目庫了,這些題目都是我收集的,看到這些

canvas+websocket+vue做一個小遊戲

做這個主要是學習使用一下canvas和websocket,專案地址。 你畫我猜大家應該都玩過,一個人畫,其他人猜。現在剛剛實現了最基本的功能,以後還會慢慢修改的。 完成進度 登入,登入後username儲存到了sessionStorage中。 座位,登入後

Java課程設計之

這幾天要做資料結構的課程設計,寫了幾天終於完成,雖然有很多不足之處,但勉強完成了。過後感覺從大一到現在寫過許多項 目,是該總結一下那些年的課程設計了。   大一做的課程設計是“你畫我猜”,那時候修修改改,前後用了一個月的時間,資料庫方面是凡神做的,最後的成績還不錯。下面總

React+Nodejs+Socket+Webpack版

React版我畫你猜 之前有看到過一個Vue版本的 我畫你猜 然後用 React 也做了一個。技術棧:React + Nodejs + Socket.io + Webpack + Less 先上

騰訊雲搭建多終端《》Socket伺服器

結合一個小demo,分享如何用騰訊雲的Socket伺服器代理各種socket請求,實現低延遲,和不同端之間的互動 作者:金朝麟  文章出處:騰雲閣文章 ---------------------------------------------------- 專案概述

谷歌AI版“”背後是什麼樣的原理?

我們先看看這個小程式是什麼,開啟微信小程式搜尋頁面,搜尋“猜畫小歌”,開啟這個小程式,點選開始作

---websocket

前段時間接觸了websocket,具體的就不介紹了,他就是與後臺建立長連線,完成資訊的傳送與接受,有興趣看我之前的blog或者google一下!之前完成了單聊與多聊的功能,分別實用tomcat7和to

Java小程式之

package com.huaxin.client; import java.awt.BasicStroke; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.Gr

iOS 小遊戲專案——升級版

級別: ★☆☆☆☆ 標籤:「iOS」「小遊戲專案」「你話我猜」 作者: MrLiuQ 審校: QiShare團隊 前言:最近公司部門在組織團建,需要準備兩個團建小遊戲, 分別是“數字速算升級版”和“你話我猜升級版”。 小編琢磨了一下,發現這個兩個小專案很適合iOS入門學習,故這篇文章誕生了。 本

一對一聊天系統核心功能實現方式有哪些,哪種方式可取?

一對一社交平臺我們可以在應用商店裡看到很多,他們都屬於一對一聊天系統的範疇,只是功能各異,各有各的產品定位及運營特色。然而它們有一個共同的核心功能:使用者間的一對一視訊(或語音)聊天。那麼各具特色的一對一聊天系統,它的核心功能是如何實現的呢? 常見的一對一聊天功能的實現方式有以下幾種: 1.

Android Accessibility(輔助功能) --實現Android應用自動安裝、解除安裝

     對於那些由於視力、聽力或其它身體原因導致不能方便使用Android智慧手機的使用者,Android提供了Accessibility功能和服務幫助這些使用者更加簡單地操作裝置,包括文字轉語音、觸覺反饋、手勢操作、軌跡球和手柄操作。開發者可以搭建自己的Accessibi

基於環信實現android客戶客服聊天功能

本來類似於這種第三方的功能是沒有必要寫部落格的,但是由於環信客服功能的文件實在版本過舊,所以在此記錄下,希望能給大家帶來一點便利。 工具:androidStudio 第1步: 註冊一個環信的賬號,地址如下,有了直接登入就可以了。https://kefu.eas

第一章 “要點爆”微信小程式雲開發之專案建立與的頁面功能實現

第一章 “我要點爆”微信小程式雲開發之專案建立與我的頁面功能實現 開發環境搭建使用自己的AppID新建小程式專案,後端服務選擇小程式·雲開發,點選新建,完成專案新建。 新建成功後跳轉到開發者工具介面 新建後,微信端為我們提供了一個參考的模板程式,這裡我們自己來建

Java 做個“手機”的小遊戲

> 本文適合有 Java 基礎的人群 ![](https://img2020.cnblogs.com/blog/759200/202009/759200-20200923184426141-1352914100.gif) 作者:**DJL-Lanking** HelloGitHub 推出的[《講

unity_小功能實現客戶相互通信功能

直接 endpoint 客戶端和服務器端 network hat sockets odi family void 服務器端:在VS中新建項目,用於服務器的搭建 using System;using System.Collections.Generic; using

Android服務開發------二級評論表的實現

前言:對於專門開發android端或者服務端某一端的開發者來說,對另一方可能也不太熟悉,希望通過這篇文章使大家更加熟悉另外一端,讓開發協作變得更加默契。 web伺服器端和app伺服器端的區別: 幾乎一樣,不過作為app,以下幾點是需要考慮的: 1、使用者的手機流量,由於手機套餐流量是一定

java服務,微信支付功能實現

     接入微信的支付功能在java服務端,現在記錄下來這個過程,方便以後用到。程式碼都是參考網路,功能可以實現      實際參考https://github.com/wxpay/WXPay-SDK-Java     ①,寫一個介面,作為引數配置的介面,當然也可以不用介

java服務對多個客戶的群聊功能程式碼實現

以下程式碼可以實現服務端傳送一條訊息,多個客戶端可以同時收到這條訊息,同時客戶端可以單獨的和服務端通訊 需要注意的是,此時服務端只需要一個傳送訊息的程序 服務端程式碼: /** * 實現多個客戶端對應一個服務端進行通訊 * * @author wa