I’m building a classic Pong style for Android game, and I wanted to implement a fun feature an image based score counter using ImageView
and drawable resources. But something weird happened the game compiled and ran fine at first, but crashed every single time the ball reached the edge of the screen.
Here’s how I tracked down the issue, fixed it, and added even more functionality along the way.
The Problem: NullPointerException
When the ball hit the top or bottom edge, my app crashed with this error:
E/AndroidRuntime: FATAL EXCEPTION
java.lang.NullPointerException at com.Pong.GameState.update(GameState.java:154)
The code causing this was:
TopCounter.setImageResource(myImageList[i+1])
Clearly, TopCounter
was null
at this point but why
Understanding the Cause
I had this line in my game thread:
_state = new GameState();
But here’s the thing GameState
was extending Activity
, and by manually calling new GameState()
, I completely bypassed Android’s lifecycle, meaning onCreate()
(where I initialize views with findViewById()
) was never called.
As a result, both TopCounter
and BottomCounter
remained null
.
The Fix
I had two solid options, and I went with the cleanest one separating game logic from UI by turning GameState
into a plain Java class (not an Activity
) and using a listener callback to update the UI from my main activity.
Refactoring My GameState Class
First, I removed extends Activity
from GameState
and stripped out all UI logic. Then I added this callback interface:
public interface ScoreListener {
void onTopScore(int score);
void onBottomScore(int score);
}
In GameState
, I held a reference to a listener:
private ScoreListener listener;
public void setScoreListener(ScoreListener l) {
listener = l;
}
Then, inside the android game update logic, I notified the listener when a score changed:
if (_ballY > _screenHeight) {
_toppoint++;
if (listener != null) listener.onTopScore(_toppoint);
}
Now, in my Activity
or GameView
, I implemented the ScoreListener
like this:
gameState.setScoreListener(new GameState.ScoreListener() {
@Override
public void onTopScore(int score) {
TopCounter.setImageResource(myImageList[score]);
}
@Override
public void onBottomScore(int score) {
BottomCounter.setImageResource(myImageList[score]);
}
});
No more NullPointerException
, and my score updates as expected.
Adding More Game Feature
Once the scoring system worked, I added some fun and useful features:
Win Condition
When a player reaches 9 points:
if (_toppoint == 9 || _bottompoint == 9) {
// Show "You Win!" or "You Lose!" message
// Stop the game loop
}
Restart Button
I added a restart button in my layout and used a method like this to reset the game:
public void resetGame() {
_ballX = _screenWidth / 2;
_ballY = _screenHeight / 2;
_toppoint = 0;
_bottompoint = 0;
if (listener != null) {
listener.onTopScore(0);
listener.onBottomScore(0);
}
}
Sound Effects
I used SoundPool
to add sounds for bouncing, scoring, and winning. It really brought the game to life!
Final Thought
Debugging this issue reminded me how tightly coupled logic and UI can cause subtle bugs, especially in Android. The key takeaway? Never instantiate an Activity
manually, and always separate game logic from UI handling. By refactoring with a listener pattern, not only did I fix the crash, but I also made the code cleaner, easier to test, and more scalable.