#java #android #nullpointerexception #try-finally
#java #Android #исключение nullpointerexception #попробуйте-наконец
Вопрос:
Я пытаюсь создать игру для Android, и я следую нескольким примерам кода, чтобы заставить мой игровой цикл работать. Это включает в себя создание нового потока. В run()
методе у меня есть блок try / finally. После выполнения блока finally выдается NullPointerException
. Я понятия не имею, почему, ничто не кажется нулевым, и даже если это так, ничто не ссылается ни на что нулевое. Я думал, что, возможно, this
было null, но, похоже, это не так. Вот код, который, я думаю, имеет отношение к делу:
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();
}
Спасибо!
Комментарии:
1. Трассировка стека скажет вам — вот для чего это нужно. По крайней мере, опубликуйте его здесь, чтобы мы могли на него взглянуть.
2.
this
никогда не может бытьnull
. Это невозможно.
Ответ №1:
NPE генерируется внутри блока try и становится видимым после выполнения блока finally.
Судя по коду, это происходит, скорее всего, потому, что c
это null
происходит, когда вы передаете его в updateAll
. У вас есть null
проверка внутри блока finally — так что, я полагаю, вы ожидаете, что оно может быть нулевым. Добавьте еще одну проверку в блок try и обработайте c == null
там тоже.
Из Android API ( SurfaceHolder#lockCanvas
):
Возвращается null, если поверхность не была создана или иным образом не может быть отредактирована
Комментарии:
1. Имеет смысл, но c не равен null при возникновении исключения с нулевым указателем
2. @robev — добавьте catch для NPE и распечатайте или запишите stacktrace, чтобы узнать, кто запускает NPE.
3. Я все равно добавил проверку, и все еще возникает исключение
4. @robev — если
c
значение не равно null, то NPE выбрасывается либо вupdateAll()
, либо вdrawAll(c)
.5. Моя главная проблема заключалась в том, откуда исходил NPE, теперь я знаю блок try 🙂 спасибо
Ответ №2:
Попробуйте заменить c = holder.lockCanvas(null);
на c = holder.lockCanvas();
И, конечно, вы должны опубликовать свой stacktrace.
Комментарии:
1. Трассировка стека была бесполезна, вот почему я не опубликовал это: Поток [<17> Поток-9] (Приостановлен (исключение NullPointerException)) MainThread.run() строка: 52
2. @robev, трассировки стека никогда не бывают бесполезными, вам просто нужно знать, как читать. Даже трассировка стека с отключенными символами отладки (без номеров строк) указывает, что такое стек вызовов методов, который имеет тенденцию значительно сужать возможные проблемные области.