在lockcanvas之后,在线程中睡眠后UI会挂起

时间:2013-11-16 22:24:52

标签: android multithreading surfaceview

我正在尝试在android上实现分形渲染器。它使用SurfaceView显示结果。

我使用单独的Thread进行渲染以在处理期间保持UI工作,但它会锁定直到调用unlockCanvasAndPost。这是预期的行为吗?如何防止用户界面锁定? 在这个例子中,我通过Thread.sleep来模拟长处理。

我的SurfaceView-Class看起来像这样:

public class MyView extends SurfaceView implements SurfaceHolder.Callback {

RenderThread rt = null;

public MyView(Context context, AttributeSet attrs) {
    super(context, attrs);
    getHolder().addCallback(this);
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
        int height) {
}

@Override
public void surfaceCreated(SurfaceHolder holder) {
    // TODO Auto-generated method stub
    rt = new RenderThread(holder);
    rt.start();
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
    rt.setStop();       
}
}

这是RenderThread-class:

public class RenderThread extends Thread {
SurfaceHolder holder;
boolean running = true;

public RenderThread(SurfaceHolder holder) {
    this.holder = holder;       
}

public void setStop() {
    running = false;
}

@Override
public void run() {
    while(running) {
        Canvas canvas = holder.lockCanvas();

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if(canvas == null) return;

        Paint p = new Paint();
        p.setARGB(255, 255, 0, 0);
        canvas.drawLine(0, 0, 100, 100, p);
        holder.unlockCanvasAndPost(canvas);
    }
}
}

1 个答案:

答案 0 :(得分:1)

几种可能性。

您没有展示如何将MyView类合并到包含它的活动中。因为您已经将SurfaceView子类化,所以您必须在活动中添加代码以专门处理您使用RenderThread添加的内容。例如,活动的onPause()方法应该向MyView类发送信号以停止其RenderThread。

SurfaceHtroyed()方法在SurfaceHolder表面被销毁之前被调用。在RenderThread停止触摸之前,您无法从该方法返回。这是通过同步完成的。 Official Android documentation for surfaceDestroyed()

有一个很好的例子,说明如何在ApiDemos项目的WindowSurface.java中正确完成所有这些操作(对于Eclipse,通过Android SDK Manager安装“Samples for SDK”)。将项目加载到Eclipse后(使用File-> New-> Project-> Android Sample Project),在项目中的com.example.android.apis.graphics中找到WindowSurface.java。

最后,如果您在线程的run方法中的实际代码(为了简洁起见,您已经使用Thread.sleep替换了这些代码)对画布执行了任何操作,那么您对canvas == null的检查应该紧接在尝试之下锁定那个画布。理想情况下,无论如何都是更好的形式。