【问题标题】:NullPointerException thrown after finally block completes在 finally 块完成后抛出 NullPointerException
【发布时间】:2026-02-09 05:10:02
【问题描述】:

我正在尝试制作一款 Android 游戏,并且我正在关注一些代码示例以使我的游戏循环正常工作。它涉及制作一个新线程。在run() 方法中,我有一个try/finally 块。在 finally 块执行后,会抛出 NullPointerException。我不知道为什么,似乎没有什么是空的,即使它是空的,也没有什么引用任何空的。我想也许this 是空的,但似乎不是。这是我认为相关的代码:

public class MainThread extends Thread {
private boolean running;
private final SurfaceHolder holder;

private boolean GameIsRunning = false;

private int mMode;
public static final int STATE_LOSE = 1;
public static final int STATE_PAUSE = 2;
public static final int STATE_READY = 3;
public static final int STATE_RUNNING = 4;
public static final int STATE_WIN = 5;

private MainGame game;

public MainThread(SurfaceHolder holder, MainGamePanel panel) {
    super();
    this.holder = holder;
    game = new MainGame(panel.getContext());
    mMode = STATE_RUNNING;
}

@Override
public void run() {
    while (running) {
        Canvas c = null;
        try {
            c = holder.lockCanvas(null);
            synchronized (holder) {
                if (mMode == STATE_RUNNING) {
                    updateAll();
                }
                drawAll(c);
            }
        } finally {
            // do this in a finally so that if an exception is thrown
            // during the above, we don't leave the Surface in an
            // inconsistent state
            if (c != null) {
                holder.unlockCanvasAndPost(c);
            }
        } // <<<<<<<<<<<<< After this line executes a null pointer exception is thrown
    } 
}

创建线程:

public class MainGamePanel extends SurfaceView implements SurfaceHolder.Callback{

private MainThread thread;

public MainGamePanel(Context context) {
    super(context);
    getHolder().addCallback(this);

    // create the game loop thread
    thread = new MainThread(getHolder(), this);
    setFocusable(true);
}


@Override
public void surfaceCreated(SurfaceHolder holder) {
    thread.setRunning(true);
    thread.start();
}

谢谢!

【问题讨论】:

  • 堆栈跟踪会告诉你——这就是它的用途。至少把它贴在这里,让我们看看。
  • this 不能永远null。这是不可能的。

标签: java android nullpointerexception try-finally


【解决方案1】:

NPE 被抛出到 try 块中,并在 finally 块执行后变得可见。

从查看代码来看,这很可能是因为当您将 c 传递给 updateAll 时,它是 null。您在 finally 块中有一个 null 检查 - 所以我猜您希望它可能为空。在 try 块中添加另一个检查并在那里处理 c == null


来自安卓 API (SurfaceHolder#lockCanvas):

如果表面尚未创建或无法编辑,则返回 null

【讨论】:

  • 有道理,但是抛出空指针异常时c不为null
  • @robev - 为 NPE 添加一个捕获并打印或记录堆栈跟踪以找出 正在抛出 NPE。
  • 反正我加了个检查,还是抛出异常
  • @robev - 如果c 不为空,则在updateAll()drawAll(c) 中抛出NPE。
  • 我的主要问题是 NPE 是从哪里来的,现在我知道了 try 块 :) 谢谢
【解决方案2】:

尝试将c = holder.lockCanvas(null); 替换为c = holder.lockCanvas();

当然你应该发布你的堆栈跟踪。

【讨论】:

  • 堆栈跟踪没有用,这就是我没有发布它的原因:线程 [ Thread-9] (Suspended (exception NullPointerException)) MainThread.run() line: 52
  • @robev,堆栈跟踪永远不会无用,您只需要知道如何阅读即可。即使是关闭了调试符号(没有行号)的堆栈跟踪也表明了方法调用堆栈是什么,这往往会显着缩小可能的问题区域。