【问题标题】:(SurfaceHolder.Callback) surfaceCreated never called(SurfaceHolder.Callback) surfaceCreated 从未调用
【发布时间】:2013-05-21 00:32:34
【问题描述】:

我正在开发一个使用 SurfaceView 绘制位图的 Android 游戏引擎,其框架与 LunarLander 类似。我的主游戏引擎活动设置布局,使其应该显示 SurfaceView 扩展类,如下所示:

super.onCreate(savedInstanceState);

    setContentView(R.layout.ss_layout);

    SSSurfaceView ssSurfaceView = (SSSurfaceView)findViewById(R.id.surface_view);
    SSSurfaceView.SSViewThread renderThread =
        (SSSurfaceView.SSViewThread) ssSurfaceView.getThread();    

findViewById 方法成功返回了我的 SurfaceView 扩展类的一个实例,并且我能够运行我在该类中定义的线程,该线程是在该方法中创建的,类构造函数:

public SSSurfaceView(Context context, AttributeSet attributes)
{
    super(context, attributes);

    SurfaceHolder holder = getHolder();
    holder.addCallback(this);

    thread = new SSViewThread(holder, context);
}

构造函数应该获得对关联 SurfaceHolder 的引用,然后将其传递给线程构造函数。我开始在 holder.lockCanvas(null) 返回 null 的线程运行方法中遇到问题。我在某处读到这可能意味着尚未创建表面,因此我使用在 surfaceCreated 回调中设置为 true 的布尔值添加了一个 if 语句。

    public void run()
    {
        Canvas canvas = null;
        try
        {
            canvas = holder.lockCanvas(null);
            //I added the condition below
            if(surfaceCreated)
            {
                drawAll(canvas);
            }
        }
        catch(Exception e)
        {
            Log.wtf("SurfaceView", "exception");
        }
        finally
        {
            if(canvas != null)
            {
                holder.unlockCanvasAndPost(canvas);
            }
        }
    }

这里是回调:

public void surfaceCreated(SurfaceHolder holder)
{
    surfaceCreated = true;
}

事实证明,surfaceCreated 从未被调用过。我的应用程序显示一个灰色屏幕并且什么都不做,因为 drawAll 方法从不迭代。这是要启动的 layout.xml 文件:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <com.bostonwalker.sseng.SSSurfaceView
        android:id="@+id/surface_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</FrameLayout>

编辑:这不是我的全部代码,我试图将我的示例限制在相关部分。线程在主循环中被调用,但给定时间,回调永远不会触发。

编辑:这是在 UI 线程中迭代的循环:

while(!halt)
    {
        //EDIT: Changed from .run() to .start()
        renderThread.start();
        gameThread.start();
        //Wait for both threads to proceed before continuing
        try
        {
            renderThread.join();
            gameThread.join();
        }
        catch (InterruptedException e)
        {
            //Do nothing
        }

        Thread.currentThread();
        try
        {
            Thread.sleep(2);
        }
        catch (Exception e)
        {
            //Do nothing
        }
    }

【问题讨论】:

  • 抱歉,您的while(!halt) 循环和内容看起来真的很邪恶……确定需要这样做吗?
  • 虽然这不是当前的问题,但我感谢您的关注。在这一点上,我不关心优化甚至灵活性,只关心让我的 SurfaceView 显示并触发回调。

标签: android android-canvas surfaceholder


【解决方案1】:

您的绘图线程不会循环 - 它只会运行一次并退出。 而且很可能在第一次运行时还没有创建表面。

您需要将当前拥有的代码放入某种循环中,例如(在伪代码中):

while(!done) {
   lockTheCanvas();
   drawAFrame();
   unlockTheCanvas();
   sleep(FRAME_INTERVAL);
}

然后您需要在适当的时间通过将“done”设置为 true 来终止线程; 请注意,您需要 sleep(),否则,您的线程将占用 cpu,并且永远不会终止。

【讨论】:

  • 主循环每秒激活线程 10 次,并且它至少完美地完成了该部分。我的问题是永远不会创建表面,或者至少不会触发回调。
  • 我会怀疑你如何'每秒激活线程 10 次'。您用来执行此操作的循环是否适当地产生(通过睡眠),以允许调用回调?另外,为什么有一个线程只运行一次,然后退出,然后多次调用它?就像我的伪代码示例一样,让线程连续运行直到被中断可能会更好。
  • 有点简化了,不过我把循环迭代在UI线程中贴出来了(主要活动.java)。
  • 我怀疑这是否真的能解决你的问题,但你不应该调用 Thread 的 run() 方法,因为它不会在新线程上运行它:-) 调用 start () 方法。
猜你喜欢
  • 2011-10-15
  • 1970-01-01
  • 1970-01-01
  • 2023-03-28
  • 1970-01-01
  • 1970-01-01
  • 2023-03-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多