Java 同步SurfaceHolder';s锁定画布并解锁CanvasandPost
我知道关于这个话题有很多问题,但是,我仍然对提供的答案不完全满意 情况: 我使用SurfaceHolder在另一个线程中使用drawing实现了SurfaceView,就像《开发人员指南》中建议的那样: 问题: 有时我会得到java.lang.IllegalStateException:Surface已经发布:Java 同步SurfaceHolder';s锁定画布并解锁CanvasandPost,java,android,multithreading,surfaceview,synchronized,Java,Android,Multithreading,Surfaceview,Synchronized,我知道关于这个话题有很多问题,但是,我仍然对提供的答案不完全满意 情况: 我使用SurfaceHolder在另一个线程中使用drawing实现了SurfaceView,就像《开发人员指南》中建议的那样: 问题: 有时我会得到java.lang.IllegalStateException:Surface已经发布: 调用SurfaceHolder.lockCanvas()时 或者在调用SufraceHolder.unlockCanvasAndPost()时 这意味着有时在锁定画布之前释放曲面,有
- 调用SurfaceHolder.lockCanvas()时
- 或者在调用SufraceHolder.unlockCanvasAndPost()时
private class DrawingThread extends Thread{
@Override
public void run() {
super.run();
while (!isInterrupted() && holder != null) {
Canvas drawingCanvas = null;
synchronized (this) {
if (holder.getSurface().isValid()) {
drawingCanvas = holder.lockCanvas();
}
}
if (drawingCanvas != null && drawingCanvas.getWidth() > 0) {
drawThisView(drawingCanvas);
synchronized (this) {
if(holder.getSurface().isValid()) {
holder.unlockCanvasAndPost(drawingCanvas);
}
}
}
}
}
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
if(drawingThread != null){
drawingThread.interrupt();
}
drawingThread = new DrawingThread();
drawingThread.start();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if(drawingThread.isInterrupted()){
drawingThread = new DrawingThread();
drawingThread.start();
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
drawingThread.interrupt();
}
synchronized
语句用于多个线程之间的互斥访问。如果在线程#1中执行synchronized(this)
,则尝试执行相同操作的任何其他线程都将阻塞,直到线程#1退出同步块
如果您只在一个线程中使用它,那么它就没有任何用处。当然,如果您有多个线程试图锁定和解锁曲面的画布,那么您应该首先通过不这样做来解决问题,而不是在事后尝试强制独占访问
使用interrupt()
和isThreadInterrupted()
没有太大意义。如果您想提升一个标志,告诉线程该停止运行了,那么volatile boolean
就可以了。“interrupt()
的唯一优势是,如果等待对象发出信号,它将唤醒线程。”。此外,考虑代码< ISCOD> ISCODIDED()<代码>调用:< /P>
返回一个布尔值,指示接收器是否有挂起的中断请求(true)或未挂起的中断请求(false)
(我的重点是。)您的代码允许这样的情况,“如果线程处于活动状态,但已为其引发中断,请继续,在旧线程仍在运行时创建一个新线程”
有关使用SurfaceView的一些信息,请参阅。这链接到Grafika中的一个示例,该示例根据您可以找到的表面回调启动和停止线程。经过几个小时的尝试和错误,我想我已经找到了答案。毕竟,我所要做的就是阅读android参考资料。以下是一些我弄错的重要事情:
仅检查曲面是否可以 被锁定,因此该检查可能(并且确实)失败,因为它可以看到画布 可以解锁李>SurfaceHolder.getSurface.isValid()
- 要检查是否可以调用
, 您只需检查解锁canvasandpost()
返回的lockCanvas()
是否为空canvas
null
- 如果
为画布
,则不应解锁它(如果 尝试它将引发异常)空
- 如果它不为null,则必须解锁它,否则如果您的活动试图停止(在
之后,onPause()
试图破坏SurfaceHolder
表面,但由于
被锁定,它将无法冻结,因此您会陷入死锁)画布
SurfaceView
编写的最后一段代码(不再需要try/catch块):
感谢fadden澄清了关于在另一个线程中绘制的一些要点。我也有同样的问题-在SurfaceView中使用后台线程绘制,有时,当活动关闭时,应用程序挂起。追踪显示,本例中的曲面在
lockCanvas
和unlockCanvasAndPost
之间被破坏
这种行为的原因似乎是我对文档有点误解<代码>回调。必须使用surfaceDestroyed来防止曲面被破坏(通过不从中返回),直到后台线程使用surface完成
DrawingThread drawingThread;
ReentrantLock paintLock = new ReentrantLock();
private class DrawingThread extends Thread{
public volatile boolean canDraw = true;
@Override
public void run() {
try {
while (canDraw) {
Canvas drawingCanvas = null;
paintLock.lock();
if (canDraw)) {
drawingCanvas = holder.lockCanvas();
if (drawingCanvas != null && drawingCanvas.getWidth() > 0) {
drawThisView(drawingCanvas);
holder.unlockCanvasAndPost(drawingCanvas);
}
}
paintLock.unlock();
}
}catch(IllegalStateException e){
e.printStackTrace();
canDraw = false;
}
}
}
...
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
paintLock.lock();
if(drawingThread != null) {
drawingThread.canDraw = false;
}
paintLock.unlock();
}
在单个同步语句中放置Lock、Draw和Unlock修复了异常 我是在读了这篇文章后才知道同步语句的,如果这是个坏主意,请纠正我
private class DrawingThread extends Thread{
@Override
public void run() {
super.run();
while (!isInterrupted() && holder != null) {
Canvas drawingCanvas = null;
synchronized (this) {
if (holder.getSurface().isValid()) {
drawingCanvas = holder.lockCanvas();
}
if (drawingCanvas != null && drawingCanvas.getWidth() > 0) {
drawThisView(drawingCanvas);
}
if(holder.getSurface().isValid()) {
holder.unlockCanvasAndPost(drawingCanvas);
}
} // Lock -> Draw -> Unlock in a single synchronised statement
}
}
}
谢谢你的回答。我想我明白你的意思。我将改变创建/销毁线程的方式,但我想重新表述我的主要问题:在我调用
holder.getSurface().isValid()
和holder.lockCanvas()
之间,是否有可能在我的绘图线程中曲面被销毁,我如何避免它?曲面完全有可能消失,当你在一个不同的线程中运行,并且没有告诉系统你正在使用它。你不能回避它。检查lockCanvas()
中的返回值,如果返回值为null,则不要尝试绘制。一旦你调用了lockCanvas()
,系统会保证曲面在你解锁之前不会消失。这就是我的想法,也是我试图做的,但有时我在尝试lockCanvas()
时会得到这些IllegalStateException
(曲面已被释放)。即使画布不为null,也不意味着在调用unlockCanvasAndPost()时曲面必须存在。如果系统只是忽略了我在曲面被破坏时锁定/解锁曲面的调用,我会非常满意,但这些异常会把一切都搞砸。一个曲面有多个渲染器线程会导致不愉快。同样,最好的修复方法是防止原位断裂
private class DrawingThread extends Thread{
@Override
public void run() {
super.run();
while (!isInterrupted() && holder != null) {
Canvas drawingCanvas = null;
synchronized (this) {
if (holder.getSurface().isValid()) {
drawingCanvas = holder.lockCanvas();
}
if (drawingCanvas != null && drawingCanvas.getWidth() > 0) {
drawThisView(drawingCanvas);
}
if(holder.getSurface().isValid()) {
holder.unlockCanvasAndPost(drawingCanvas);
}
} // Lock -> Draw -> Unlock in a single synchronised statement
}
}
}