简体   繁体   中英

Android - “thread exiting with uncaught exception (group=0x40015560)”

This problem seemingly appeared from nowhere, and it's been turning me insane for the past two and half hours. I've been all around the internet, looking for a solution, but my quest was in vain.

I've therefore decided to ask for help.

My Android game compiles fine, and it used to run fine, but now it doesn't. It occurred at about the time when I started adding in a few more images for use in the game.

The logged message:

01-28 20:42:34.510: WARN/dalvikvm(3857): threadid=10: thread exiting with uncaught exception (group=0x40015560)
01-28 20:42:34.510: ERROR/AndroidRuntime(3857): FATAL EXCEPTION: Thread-11
01-28 20:42:34.510: ERROR/AndroidRuntime(3857): java.lang.NullPointerException
01-28 20:42:34.510: ERROR/AndroidRuntime(3857):     at com.ballbounce.bounce.MainGamePanel.update(MainGamePanel.java:153)
01-28 20:42:34.510: ERROR/AndroidRuntime(3857):     at com.ballbounce.bounce.MainThread.run(MainThread.java:91)
01-28 20:42:34.510: WARN/ActivityManager(105):   Force finishing activity com.ballbounce.bounce/.BallBounceActivity

I think the NullPointerException happens as a result of the thread exiting, not the actual cause of the thread closing, though.

I've tried 'cleaning' the project in Eclipse, restarting Eclipse, restarting the phone... all of the usual stuff. My 'undo' function doesn't let me go back far enough to get the game to a stable state.

Relevant code (I've tried to trim as much of it down as possible):

BallBounceActivity.java

public class BallBounceActivity extends Activity {
    // Trimmed down for ease-of-viewing

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        requestWindowFeature(Window.FEATURE_NO_TITLE);

        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);

        sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        sensor = sensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER).get(0);

        mainGamePanel = new MainGamePanel(this);


        setContentView(mainGamePanel);

        PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
        wl = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, "BallBounceActivity");
    }

    protected void onPause() {
        // Trimmed down for ease-of-viewing
    }

    protected void onResume() {
        // Trimmed down for ease-of-viewing
    }

    protected void onStop() {
        // Trimmed down for ease-of-viewing
    }

    private SensorEventListener accelerationListener = new SensorEventListener() {  
        public void onAccuracyChanged(Sensor sensor, int acc) {
        }

        @Override
        public void onSensorChanged(SensorEvent event) {
            // Trimmed down for ease-of-viewing
        }

    };
}

MainGamePanel.java

public class MainGamePanel extends SurfaceView implements SurfaceHolder.Callback {
    // Trimmed down for ease-of-viewing

    private MainThread thread;

    // The Fps to be displayed
    private String avgFps;
    public void setAvgFps(String avgFps) {
        this.avgFps = avgFps;
    }

    public MainGamePanel(Context context) {
        super(context);

        getHolder().addCallback(this);

        setFocusable(true);

    }

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

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        thread = new MainThread(getHolder(), this);

        thread.setRunning(true);
        thread.start();

        random = new Random();

        bmpFactoryOptions = new BitmapFactory.Options();
        bmpFactoryOptions.inScaled = false;

        powerups = new Bitmap[12];

        // Copy and paste time!
        powerups[0] = BitmapFactory.decodeResource(getResources(), R.drawable.coin, bmpFactoryOptions);
        powerups[1] = BitmapFactory.decodeResource(getResources(), R.drawable.powerup_8, bmpFactoryOptions);
        powerups[2] = BitmapFactory.decodeResource(getResources(), R.drawable.powerup_9, bmpFactoryOptions);
        // Trimmed down for ease-of-viewing


        ballImages = new Bitmap[8];

        // Copy and paste time!

        ballImages[0] = BitmapFactory.decodeResource(getResources(), R.drawable.ball_0, bmpFactoryOptions);
        ballImages[1] = BitmapFactory.decodeResource(getResources(), R.drawable.ball_1, bmpFactoryOptions);
        ballImages[2] = BitmapFactory.decodeResource(getResources(), R.drawable.ball_2, bmpFactoryOptions);
        // Trimmed down for ease-of-viewing

        items = new ArrayList<Item>();

        theBall = new Ball(this.getWidth(), this.getHeight(), 24.0f, items, ballImages);
        platform = new Platform(this.getWidth(), this.getHeight(), 180.0f);
        player = new Player(theBall, platform);

        theBall.setPlayer(player);
        theBall.setPlatform(platform);

        x = y = 0.0f;
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        // Trimmed down for ease-of-viewing
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // Trimmed down for ease-of-viewing
    }
    public void render(Canvas canvas) {
        // Trimmed down for ease-of-viewing
    }

    public void update() {
        // Trimmed down for ease-of-viewing

        theBall.update(x, y);
        platform.update();
    }

    public void updateAccelerometerValues(float x, float y, float z) {
        // Trimmed down for ease-of-viewing
    }

    public void displayScore(Canvas canvas) {
        // Trimmed down for ease-of-viewing
    }

    public void displayFps(Canvas canvas, String fps) {
        // Trimmed down for ease-of-viewing
    }

}

MainThread.java

public class MainThread extends Thread {
    // Trimmed down for ease-of-viewing

    public MainThread(SurfaceHolder surfaceHolder, MainGamePanel gamePanel) {
        super();
        this.surfaceHolder = surfaceHolder;
        this.gamePanel = gamePanel;
    }

    @Override
    public void run() {
        Canvas canvas;
        // Trimmed down for ease-of-viewing

        sleepTime = 0;

        while (running) {
            canvas = null;

            try {
                canvas = this.surfaceHolder.lockCanvas();
                synchronized (surfaceHolder) {
                    beginTime = System.currentTimeMillis();
                    framesSkipped = 0;  

                    this.gamePanel.update();

                    this.gamePanel.render(canvas);              

                    timeDiff = System.currentTimeMillis() - beginTime;

                    sleepTime = (int)(FRAME_PERIOD - timeDiff);

                    if (sleepTime > 0) {
                        try {
                            Thread.sleep(sleepTime);    
                        } catch (InterruptedException e) {}
                    }

                    while (sleepTime < 0 && framesSkipped < MAX_FRAME_SKIPS) {
                        this.gamePanel.update(); 
                        sleepTime += FRAME_PERIOD;  
                        framesSkipped++;
                    }

                    // Trimmed down for ease-of-viewing
                }
            } finally { 
                if (canvas != null) {
                    surfaceHolder.unlockCanvasAndPost(canvas);
                }
        }
        Log.d(TAG, "Thread exited");
    }
}

R.java

public final class R {
    public static final class attr {
    }
    public static final class drawable {
        public static final int ball_0=0x7f020000;
        public static final int ball_1=0x7f020001;
        public static final int ball_2=0x7f020002;
        public static final int ball_3=0x7f020003;
        public static final int ball_4=0x7f020004;
        public static final int ball_5=0x7f020005;
        public static final int ball_6=0x7f020006;
        public static final int ball_7=0x7f020007;
        public static final int coin=0x7f020008;
        public static final int ic_launcher=0x7f020009;
        public static final int powerup_8=0x7f02000a;
        public static final int powerup_9=0x7f02000b;
        public static final int powerup_9_save=0x7f02000c;
    }
    public static final class layout {
        public static final int main=0x7f030000;
    }
    public static final class string {
        public static final int app_name=0x7f040001;
        public static final int hello=0x7f040000;
    }
}

Any ideas as to how to fix this problem, or even any suggestions as for how this happened, would be greatly appreciated.

Many thanks in advance, Will.

I came up with a solution:

The gamePanel.update() function was called by Thread-11 before the entire surfaceCreated(SurfaceHolder holder) function had completed. This meant that Thread-11 was trying to use objects before they were initialised, which of course resulted in the NullPointerException.

My fix was to add:

while(gamePanel.player == null) {
    try {
        Thread.sleep(10);
    }
    catch (InterruptedException e) {}
}

Just before the while (running) ... bit in MainThread's run() function. (The choice of 'player' was because 'player' is the last object to be initialised).

Quite an interesting problem, and an interesting solution.

I hope this solution solves a problem for some people in the future!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM