关于此主题的关键词:
- CustomSurfaceView: 为三个不同级别创建了三个自定义surfaceview。
- Canvas: lock/unlockAndPost方法 (我没有使用自定义位图)
- 多线程(每个surface都是单独的一个线程)
- 形状 (在画布上的形状)
- 客户端/服务器 (架构)
- 闪烁问题 (这就是我来到这里的原因)
我们正在开发一个客户端/服务器应用程序,我正在处理客户端方面的工作。我从服务器接收包含有关路径的一般数据(坐标、颜色、宽度[...]) 的消息,例如圆形、矩形、线条和其他形状。Web 应用程序允许用户通过 HTML5 Canvas 将这些数据发送到接收该消息并解析它的 android 设备,以便能够重新绘制所有形状。根据我的经验,在这些方面,我学到的最好的方法是把所有在画布上绘制的东西保存到缓冲区、数组、列表或类似的东西中,然后在需要时重用它 (例如,你可以使用旧路径来展示、隐藏、移动或简单地更改画布中的某些东西)。在我的看法中,android 应用程序遵循了 android 开发和面向对象编程范例的最佳实践,所以我不会假设与错误相关的架构问题。在这种情况下,我将消息保存在 web 客户端侧。当用户在 HTML5 Canvas 上绘制时,包含形状信息的消息能够完美地传递到 android 画布中,但问题出现在这里:
[举个例子] 考虑你绘制了 10 个对象(10 条消息),并且想要仅删除其中一个对象的情况下,唯一的方法是清除所有画布,并重新绘制之前的不包括已删除的形状的图形(因此通过循环消息缓冲区重新发送 9 条消息)。这种方法对于 Web 应用程序来说运作得很好,但会导致 android 客户端出现闪烁问题。因此,在进行了太多的实验后,我找到了一个解决方法,使用 Thread.sleep(100)(哇!100 毫秒太长),以便慢慢解析消息,并让 surfaceview 线程正确地读取数据(通过单例模式访问数据)并将其写入画布的双缓冲区。嗯,虽然效率很低、有些丑陋,但它确实能运作!实际上,我并不喜欢这种“可怕”的解决方法,所以请帮我找到一条出路。
这是从形状容器获取数据并在数据存在的情况下绘制画布的代码片段。每个容器的数据都来自服务器消息。
@Override
public void run() {
Canvas canvas = null;
while (running) {
//this is the surface's canvas
try {
canvas = shapesSurfaceHolder.lockCanvas();
synchronized (shapesSurfaceHolder) {
if (shapesSurfaceHolder.getSurface().isValid()) {
if(!Parser.cmdClear){
//draw all the data present
canvas.drawPath(PencilData.getInstance().getPencilPath(),
PencilData.getInstance().getPaint());
canvas.drawPath(RectData.getInstance().getRectPath(),
RectData.getInstance().getPaint());
canvas.drawPath(CircleData.getInstance().getCirclePath(),
CircleData.getInstance().getPaint());
canvas.drawPath(LineData.getInstance().getLinePath(),
LineData.getInstance().getPaint());
canvas.drawText(TextData.getInstance().getText(),
TextData.getInstance().getX(),
TextData.getInstance().getY(),
TextData.getInstance().getPaint());
} else {
//remove all canvas content and clear data.
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
for (int i = 0; i < AbstractFactory.SHAPE_NUM; i++) {
abstracFactory.getShape(i).clearData();
}
}
}
}
} finally {
if (canvas != null) {
shapesSurfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
}//end_run()
我可以总结一下,我的问题似乎是绘制得太快了。
注:
类似概念:Android线程控制多个纹理视图会导致奇怪的闪烁 启用硬件加速。
minSdkVersion 17
测试设备为:
- 三星平板 SM-T113 - 谷歌 Nexus 5
surfaceHolder.lockCanvas()
没有任何参数是可以的。 我也考虑了你的替代方案:“存储绘图命令,从初始清除开始,并在lock/unlock之间播放它们。”实现如下:canvas = surfaceHolder.lockCanvas(); for( int i = 0; i < commandList.size(); i++){ canvas.drawPath(pathList.get(i),paintList.get(i)); } surfaceHolder.unlockCanvasAndPost(canvas);
对吧? - Andrea D'UbaldolockCanvas()
unlockCanvasAndPost()
之间绘制存储的数据是解决方案。我也很想了解离屏位图的替代方法,所以(如果你愿意)能否为我提供一些示例链接?再次感谢。 - Andrea D'UbaldodrawBitmap()
调用混合位图,并解锁并发布。 - fadden