1

我正在使用 SurfaceView 绘制到屏幕的一部分,从而使用后台线程更新绘图。surfaceview 实现了一个 SurfaceView.callback。

在 onDraw 方法中,我使用 canvas.drawpont(x,y,paint) 并逐个像素地绘制到几乎整个画布,因此在大屏幕上可能会非常密集。无论如何,如果我在横向和反向横向之间快速旋转手机,我会得到一个非法参数异常。如下:

06-18 15:03:05.853: E/AndroidRuntime(29969): FATAL EXCEPTION: Thread-45
06-18 15:03:05.853: E/AndroidRuntime(29969): java.lang.IllegalArgumentException
06-18 15:03:05.853: E/AndroidRuntime(29969):    at Android.view.Surface.unlockCanvasAndPost(Native Method)
06-18 15:03:05.853: E/AndroidRuntime(29969):    at android.view.SurfaceView$3.unlockCanvasAndPost(SurfaceView.java:793)
06-18 15:03:05.853: E/AndroidRuntime(29969):    at com.enhancement.SpecGuageUpdate.run(SpecGuageUpdate.java:313)

在 313 的 SpecGugaeupdate 上,我有:

mHolder.unlockCanvasAndPost(canvas);

mHolder 是我的 SurfaceHolder。当然,在调用 onDraw 之前我也锁定了画布。

如果我在各个方向缓慢旋转,此方法将完美无缺,但是,当我在两个景观状态之间快速旋转 180 度时,它会触发此非法ArgumentException。在监控surfaceChanged中的宽度和高度时,我注意到当我快速旋转时,横向的宽度与纵向的高度配对。例如,在我的手机 (Motorola atrix) 上,SurfaceView 的纵向尺寸为 540x307 (WidthxHeight),横向尺寸为 960x172。当我在横向和反向横向之间快速旋转时会发生这种情况:

慢慢旋转到横向:

960x172

快速旋转以反转景观,表面变化被调用两次。

960x307 - 1st
960x172 - 2nd

我尝试过覆盖 onMeasure,宽度和高度与 SurfaceChanged 的​​相同。因此,我似乎正在尝试在尚未准备好但已准备好将其锁定到我的 Holder 的画布上进行绘制。任何想法都会很棒,谢谢你的时间。

此外,在我的 surfacedestroyed 中,我正在处理我的线程,如下所示:

boolean retry = true;

            thread.setRunning(false);
              while (retry) {
                    try {
                        specupdate.join();
                        retry = false;
                    } catch (InterruptedException e) {
                    }
                }

这会阻止线程执行 onDraw。

4

2 回答 2

1

我在制作动态壁纸时遇到了同样的问题。我通过强制我的画布成为屏幕大小来解决这个问题。在我的 onSurfaceChanged 上,我创建了一个全局矩形,我用它来在我的画布上疼痛。如果我不这样做,我会遇到与原作者相同的问题。

解决它的代码:

在 Surface Changed 上,我初始化了用于绘图的所有变量。注意我创建 _screenRectangle。这些变量是全局变量并在整个应用程序中使用。

@Override
public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    super.onSurfaceChanged(holder, format, width, height);

    System.out.println("===============================================");
    System.out.println("SURFACE CHANGED");
    System.out.println("===============================================");

    //Get Screen Sizes
    _centerX = width/2.0f;
    _centerY = height/2.0f;

    _screenRectangle = new Rect(0, 0, width, height);
    _screenOrient = getResources().getConfiguration().orientation; 

    System.out.println("===============================================");
    System.out.println("WIDTH: " + width + " HEIGHT: " + height + " ORIEN: " + _screenOrient);
    System.out.println("===============================================");

    _resetSurface = true;
    _redrawStatic = true; 
} 

然后在我的绘画方法中,我使用背景颜色绘制整个屏幕:

try
{            
    canvas = holder.lockCanvas(_screenRectangle);


    System.out.println("===============================================");
    System.out.println("PAINT BACKGROUND: " + canvas.getWidth() + " " + canvas.getHeight());
    System.out.println("===============================================");

    if (canvas != null) 
    {
        canvas.drawColor(PreferencesHelper.ScreenColor);
        _resetSurface = false;
    }
}
finally 
{
    System.out.println("===============================================");
    System.out.println("BACKGROUND PAINTED");
    System.out.println("===============================================");
    if (canvas != null) holder.unlockCanvasAndPost(canvas);
}

在使用 _screenRectangle 锁定画布之前,它会随机绘制整个屏幕失败。调试窗口将显示画布尺寸与当前屏幕不匹配,但会出现与 OP 指出的相同的问题 这似乎已经解决了这个问题。这会强制锁定的画布与 onSurfaceChanged 方法报告的大小相同。

于 2012-07-17T01:09:37.613 回答
0

在我深夜的故障排除中,我设法整理了一个解决方法。结果是在surfacechanged 稳定到它的最后一个状态之前什么都不会被绘制,所以用户不知道发生了什么。

基本上我会检查返回的高度是否格式错误,如果是我什么都不做,当它是我期望的时候我绘制到表面。我需要的是我的高度和宽度的参考值,我通过在我的主要活动中的 SetContentView() 之前放置以下代码来做到这一点:

WindowManager w = getWindowManager();
   Display d = w.getDefaultDisplay();
   int Meausredwidth = d.getWidth();
   int Measuredheight = d.getHeight(); 

根据我测量的高度和宽度,我计算出我需要多少 SurfaceView,并将这些值作为全局变量传递给我的 SurfaceView(这些现在是我想要的尺寸)。确保我也在我的主要活动中调用 onconfigurationchanged() 中的上述代码,以便每次都重新计算这些值。在实现 SurfaceHolder.Callback 的 SurfaceView 上,我将 surfacechanged() 更改为如下所示:

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

    if (width != mWidth) {
        MalFormed = true;
        thread.setRunning(false);
        count++;

    } else if (width == mWidth) {

        if (MalFormed) {
            MalFormed = false;

            Log.d("ROTATE", "ReDraw");

            thread = new DrawingThread(this, holder, mHandler);
            thread.setRunning(true);
            thread.start();

        }

    }

}

其中 mWidth 是所需的宽度。在我的表面视图中,MalFormed 是一个全局布尔值。通过实验,我发现 SurfaceChanged() 在 SurfaceCreated 之前被调用,这意味着我们可以轻松修改任何尝试与线程交互的代码以适应我们的上述更改。

因此,在我尝试加入或启动该背景绘图线程的其他任何地方,我都需要首先检查表面是否为 MalFormed。例如

if (thread.getState() == State.TERMINATED){

            if(!MalFormed){
               holder.removeCallback(this);
               holder = getHolder();
               holder.addCallback(this);


               thread = new DrawingThread(this, holder,mHandler);
               thread.setRunning(true);

               thread.start();
            }



        }else{
            if(!MalFormed){
                thread.setRunning(true);

                try {
                    thread.join();
                } catch (InterruptedException e) {

                    e.printStackTrace();
                }
            }


        }

无论如何,这似乎可以解决问题,也许其他人知道更好的事情。但我把我的答案放在这里给有同样问题的其他人。谢谢。

于 2012-06-18T09:17:29.293 回答