年初的时候刚把去年底的一个电子书包的项目完结了,这不刚过了几天又收到了boss新的需求:添加一个电子白板,要求老师端绘画的时候,学生端的屏幕也能看到老师端的操作。
难点:
1.画板的写法
2.如何推送数据到学生端,该推送什么格式的数据
3.学生端收到数据该如何绘制。
思路:
1.画板的写法ok,网上一大堆
2.老师端绘制的时候,绘制的每一个操作,又都横纵坐标记录,我只要推送这些记录给学生端,让学生端再根据 坐标绘制
3.依然采取1.0的方案,客户端用socket(tcp)服务器端用(walkman)方式推送数据(已解决)
方案:
1.画板采用github上星星最多的AndroidDrawingView,前人种树好乘凉,我的建议是最好下载源码自己先看一遍他的思路,当然这里我早就发现这个demo完全契合我的项目。这个demo竟然已经为你扩展了如何实现同屏。请看
DrawingView.java里的这个接口:
/**
* 绘制代理,通知状态变更和获取数据
*/
public interface DrawingStepDelegate {
/**
* 当前绘制step创建时回调,通常用于远程同步
* step处于变化状态
*
* @param drawingView 当前view
* @param step 当前绘制step,任意修改此step可能导致错误
*/
void onDrawingStepBegin(DrawingView drawingView, DrawingStep step);
/**
* 当前绘制step变更时回调,每次touch绘制都会执行,text图层修改内容也会执行,此回调执行频繁,通常用于远程同步
* step处于变化状态
*
* @param drawingView 当前view
* @param step 当前绘制step,任意修改此step可能导致错误
*/
void onDrawingStepChange(DrawingView drawingView, DrawingStep step);
/**
* 当前绘制状态已改变,绘制一笔或进行撤销/重做/清空等变更记录数据的操作都会触发此回调
* step已经完成
*
* @param drawingView 当前view
* @param step 当前绘制step,任意修改此step可能导致错误
*/
void onDrawingStepEnd(DrawingView drawingView, DrawingStep step);
/**
* 当前step撤销
*
* @param drawingView 当前view
* @param step 当前绘制step,任意修改此step可能导致错误
*/
void onDrawingStepCancel(DrawingView drawingView, DrawingStep step);
}
很明显,当我在DrawingView上绘图时会触发这个接口里的四个方法,我想这里就应该是我想要的坐标数据,我只要推送这些数据就行了,那么问题来了,现在我推送只能推送json数据,接收的时候再转成我想要的类,那么DrawingStep如何才能变json呢,点到DrawingStep类里你就回恍然大悟,才会发现此人早就替你想好这一点。原来这个类本身就是个json解析类。他的思路应该是这样的,绘画的时候每一步记录坐标(JSon数据)——解析成DrawingStep——然后drawingView根据DrawingStep绘制,DrawingData存放DrawingStep的集合。既然它是个解析Json的类,那么自然有类转JSon的方法
/**
* 复制step
* @return 复制的step
*/
public DrawingStep copy() {
return new Json<>(this.getClass()).modelFromJson(this.toJson());
}
dv.setDrawingStepDelegate(new DrawingView.DrawingStepDelegate() {
@Override
public void onDrawingStepBegin(DrawingView drawingView, DrawingStep step) {
//drawingView.getDrawingData().addDrawingStep(step);
Logger.i("画板操作onDrawingStepBegin::"+step.toJson().toString());
SendOrderBean sendOrderBean=new SendOrderBean("userSendPositionRequest",JSON.toJSONString(new UserSendPositionRequest("4450187",step.toJson().toString())),System.currentTimeMillis()+"");
singleSocket.sendMessage(JSON.toJSONString(sendOrderBean));
}
@Override
public void onDrawingStepChange(DrawingView drawingView, DrawingStep step) {
Logger.i("画板操作onDrawingStepChange::"+step.toJson().toString());
SendOrderBean sendOrderBean=new SendOrderBean("userSendPositionRequest",JSON.toJSONString(new UserSendPositionRequest("4450187",step.toJson().toString())),System.currentTimeMillis()+"");
singleSocket.sendMessage(JSON.toJSONString(sendOrderBean));
}
@Override
public void onDrawingStepEnd(DrawingView drawingView, DrawingStep step) {
Logger.i("画板操作onDrawingStepEnd::"+step.toJson().toString());
SendOrderBean sendOrderBean=new SendOrderBean("userSendPositionRequest",JSON.toJSONString(new UserSendPositionRequest("4450187",step.toJson().toString())),System.currentTimeMillis()+"");
singleSocket.sendMessage(JSON.toJSONString(sendOrderBean));
}
@Override
public void onDrawingStepCancel(DrawingView drawingView, DrawingStep step) {
Logger.i("画板操作onDrawingStepCancel::"+step.toJson().toString());
SendOrderBean sendOrderBean=new SendOrderBean("userSendPositionRequest",JSON.toJSONString(new UserSendPositionRequest("4450187",step.toJson().toString())),System.currentTimeMillis()+"");
singleSocket.sendMessage(JSON.toJSONString(sendOrderBean));
}
});
/**
* 在当前绘制基础上增加绘制传入的step,如果传入的step与当前未完成的step是同一step(编号相同,远程同步step可能有未完成和已完成两种状态),更新当前step
*
* @param step 将要绘制的step
*/
public void drawNextStep(@NonNull DrawingStep step) {
step.setRemote(true);
if (step.getStep() != getCurrentDrawingStep().getStep()) {
endUnfinishedStep();
getDrawingData().addDrawingStep(step);
} else {
getDrawingData().replaceDrawingStep(step);
}
if (step.isCanceled()) {
internalCancelCurrentStep();
getDrawingData().cancelDrawingStep();
} else {
internalUpdateCurrentStep(false);
}
}
/**
* 在当前绘制基础上增加绘制传入的step,此step必须是stepOver状态
* 在远程同步绘制时,采用低频同步,仅在每一步绘制完成后同步时调用此方法
* 不可与{@link #drawNextStep(DrawingStep)}同时使用
*
* @param step 将要绘制的step
*/
public void drawNextOverStep(@NonNull DrawingStep step) {
if (!step.isStepOver()) {
return;
}
getDrawingData().addDrawingStep(step);
if (step.isCanceled()) {
return;
}
internalUpdateCurrentStep(true);
}
那么接下来就是soeasy了:
private void initBroadCastReceiver() {
IntentFilter filter = new IntentFilter();
filter.addAction("SOCKET_MESSAGE");
if (receiver==null){
receiver=new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("SOCKET_MESSAGE")) {
Bundle data = intent.getBundleExtra("data");
String msg = data.getString("message", "none");
Log.i("服务器返回信息::", msg);
try {
ReceiveOrderBean receiveOrderBean = JSON.parseObject(msg, ReceiveOrderBean.class);
switch (receiveOrderBean.getType()) {
case "userSendPositionReceive":
Toast.makeText(TestActivity.this,"获取到坐标数据",Toast.LENGTH_SHORT).show();
// Logger.i("获取到坐标数据"+receiveOrderBean.getData());
DrawingStep drawingStep = new Json<>(DrawingStep.class).modelFromJsonString(receiveOrderBean.getData());
Logger.i("获取到坐标数据"+drawingStep.toJson().toString());
dv.drawNextStep(drawingStep);
dv.drawNextOverStep(drawingStep);
// dv.getDrawingData().addDrawingStep(drawingStep);
// dv.refreshWithDrawingData(dv.getDrawingData());
break;
}
} catch (com.alibaba.fastjson.JSONException ex) {
Log.i("命令解析出错", msg + "");
}
}
}
};
App.localBroadcastManager.registerReceiver(receiver, filter);
}
}
dv.setDisableTouchDraw(true);//true是设置不能画,false反之