SurfaceView闪烁/撕裂

时间:2010-08-26 07:42:18

标签: android rendering flicker surfaceview tearing

我正试图弄清楚如何解决我的问题。我已经阅读了http://groups.google.com/group/android-developers/browse_thread/thread/a2aac88a08cb56c2/b7dff4ba388cd664?lnk=gst&q=SurfaceView#b7dff4ba388cd664我的问题的答案,但就我所知,这是一种“艰难的运气”答案。所以这是我的问题:

我正在以正常方式使用SurfaceView(lock / unlockAndPost)在表面更改时绘制我的游戏背景位图(例如方向等)并且我渲染一系列移动圆圈(最多30个带有半径约为25.f)。这些圈子的位置的x,y数据来自服务器,并且一切正常。 所有圆形对象都存储在列表中,并且它们的位置会更新,以确保同步更新。 然而,当我将这些圆圈绘制到屏幕上时(在canvas.lock()期间),大多数时候它们渲染得很好但偶尔(例如每隔几秒一次),一些圆圈看起来像一帧一样地撕裂或闪烁。圆的数量总是不变的,所以这不是问题,并且没有对圆列表的并发修改(正如我所说,它是同步的)。 我甚至尝试将所有这些圆形绘制到每个渲染循环上的位图并将该位图绘制到主画布上。这似乎只会影响性能(~13FPS,而不是直接将圆圈绘制到主画布时的〜30FPS)。 对不起,如果这些信息有点模糊,(试图让公司高兴:p)但我只是想知道是否有人能给我一个线索?或者我只是运气不好。我应该注意到来自服务器的定位数据是实时数据,渲染反映这些实时位置至关重要。

感谢您的帮助! 克里斯

编辑:

足够公平。这是来自渲染线程的run()。

@Override
    public void run() {
        Canvas c;
        while (mRun) {
            c = null;
            try {
                c = mSurfaceHolder.lockCanvas(null);
                synchronized (mSurfaceHolder) {
                    panel.onDraw(c);
                }
            } finally {
                if (c != null) {
                    mSurfaceHolder.unlockCanvasAndPost(c);
                }
            }
        }
    }

相当标准的东西(几乎是月球着陆器的副本:p)

@Override
public void surfaceCreated(SurfaceHolder holder) {
    mBackground= Bitmap.createBitmap(this.getWidth(), this.getHeight(), Bitmap.Config.RGB_565);
    screenOrientation = getResources().getConfiguration().orientation;
    if(thread.getState()== Thread.State.TERMINATED){
        thread = new RenderThread(holder, this);
        thread.setRunning(true);
        thread.start();
    }else {
        thread.setRunning(true);
        thread.start();
    }
}



@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
        int height) {
    Canvas c = new Canvas(mField);
    c.drawARGB(255,0,144,0);
    backgroundDetails.renderOnPanel(c, this);
    screenOrientation = getResources().getConfiguration().orientation;
}

非常容易理解,只需在方向改变时重绘背景位图并启动渲染线程。

public void onDraw(Canvas canvas) {
    canvas.drawBitmap(mField,0,0,null);
    drawPositionBeans(canvas, this);
}

最后:

    public void onDraw(Canvas canvas, RadarView radarView) {
    float beanX=0, beanY=0;
    float radius = 25.0f;
    final List<PositionBean> copyOfList = Collections.synchronizedList(positionBeans.getPositionBeans());
    synchronized(copyOfList){
        try {
            for (final PositionBean pb : copyOfList)
            {
                if (panel.getOrientation() == Configuration.ORIENTATION_PORTRAIT) {
                    beanX = (float)pb.getY()*(-1);
                    beanY = (float)pb.getX();
                } else {
                    beanX = (float)pb.getY()*(-1);
                    beanY = (float)pb.getX()*(-1);
                }
                mPaint.setARGB(255,pb.getRgbColor().getR(), pb.getRgbColor().getG(), pb.getRgbColor().getB());
                panel.drawSpot(canvas, beanX, beanY, radius, mPaint);

                mPaint.setStyle(Paint.Style.STROKE);
                mPaint.setARGB(255,255,222,1);
                for (int j = 0; j < selectedBean.size(); ++j)
                {
                    if(pb.getTrack()==selectedBean.get(j)) {
                        panel.drawSpot(canvas, beanX, beanY, radius+1, mPaint);
                    }
                }
                mPaint.setStyle(Paint.Style.FILL);
            }

        } catch(Exception e) {
            Log.e("render", "Exception Drawing Beans: " + e);
        }
    }
}

再次感谢你们。 克里斯

4 个答案:

答案 0 :(得分:1)

这是因为Android图形具有缓冲表面和可见表面,并确保它们始终可用,它们只是交替。这意味着如果你在一个画面上画画,除非你在每一帧上画画,否则它不会在那里画画。

http://groups.google.com/group/android-developers/msg/8d1243c33f9b7b6e?pli=1

答案 1 :(得分:1)

这是一个很好的解释和可能的解决方法

http://android-coding.blogspot.ca/2012/01/flickering-problems-due-to-double.html

答案 2 :(得分:0)

我遇到了这个问题。适合我的解决方案是onDraw方法和更新转换矩阵的方法的同步。因为当矩阵相同时(新Matrix()的初始值)存在帧,并且在下一帧中它具有正确的值。

答案 3 :(得分:0)

我在阅读了一些表面视图后发现,如果你打电话

getHolder().lockCanvas();

你需要再画一遍。

除非你提供脏区。

getHolder().lockCanvas(Rect dirty);

如果您只想重绘Rect

定义的区域