Page 1 of 1

[Solved]My Android app crashes at exit (and screen rotation)

Posted: Sun Feb 02, 2014 4:53 pm
by superLED
Hi there!

I've struggled with this for some months now. I've just been ignoring it, because it hasn't been to much of a problem to me, but now I'm ready for release, and would like to fix it up.

The problem is that when I'm in the game, and click the Home button, the gameLoop thread (I guess) fucks up and then it pops up "Unfortunately, <app name> has stopped."
It also crashes when I rotate the screen (not too much of a problem, because I have fixed orientation, but would like to fix it for future projects)
I have very little experience with Java and Android development, so please keep that in mind.

I've made a very simple program where this problem occurs. All the program does is showing a number on the screen, and increasing it when you touch the screen.

Error message:

Code: Select all

FATAL EXEPTION: Thread-23207
java.lang.NullPointerExeption
at com.example.crashtest.GameView.onDraw(GameView.java:61)
at com.example.crashtest.GameLoopThread.run(GameLoopThread.java:34)
Here's the code:

MainActivity.java

Code: Select all

package com.example.crashtest;

import android.media.AudioManager;
import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
import android.view.KeyEvent;
import android.view.Window;

public class MainActivity extends Activity {
	private AudioManager am;
	
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(new GameView(this));
        
        am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
    }
    
    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
    }
    
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        switch (keyCode) {
	        case KeyEvent.KEYCODE_BACK:
	        	return true;
	        	
	        case KeyEvent.KEYCODE_MENU:
	        	return true;
	        	
	        case KeyEvent.KEYCODE_VOLUME_UP:
	        	am.adjustStreamVolume(AudioManager.STREAM_MUSIC,
	                    AudioManager.ADJUST_RAISE, AudioManager.FLAG_SHOW_UI);
	            return true;
	            
	        case KeyEvent.KEYCODE_VOLUME_DOWN:
	        	am.adjustStreamVolume(AudioManager.STREAM_MUSIC,
	                    AudioManager.ADJUST_LOWER, AudioManager.FLAG_SHOW_UI);
	            return true;
	            
	        default:
	            return false;
        }
    }
}
GameView.java

Code: Select all

package com.example.crashtest;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class GameView extends SurfaceView {	
	private SurfaceHolder holder;
	private GameLoopThread gameLoopThread;
    
	private int num = 0;
	
	public GameView(final Context context) {
		super(context);
		
		holder = getHolder();
		holder.addCallback(new SurfaceHolder.Callback() {
			
			@Override
            public void surfaceDestroyed(SurfaceHolder holder) {
					
                   boolean retry = true;
                   gameLoopThread.setRunning(false);
                   while (retry) {
                          try {
                                gameLoopThread.join();
                                retry = false;
                          } catch (InterruptedException e) {}
                   }
            }
			
			@Override
			public void surfaceCreated(SurfaceHolder holder) {
				
				makeThread();
				gameLoopThread.start();
				gameLoopThread.setRunning(true);
			}
			
			@Override
			public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
				
			}
		});
	}
	
	private void makeThread() {
		gameLoopThread = new GameLoopThread(this);
	}
	
	@SuppressLint({ "WrongCall", "DrawAllocation" })
	@Override
	protected void onDraw(Canvas canvas) {
		// Draw black background - Write variable 'num' on the screen
		canvas.drawColor(Color.BLACK);
		
		Paint paint = new Paint();
		paint.setARGB(255, 0, 255, 0);
		paint.setTextSize(50);
		paint.setTextAlign(Align.CENTER);
		
		canvas.drawText(Integer.toString(num), getWidth() / 2, getHeight() / 2, paint);
	}
	
	public boolean onTouchEvent(MotionEvent event) {
		if(event.getAction() == MotionEvent.ACTION_DOWN) {
			// Increase 'num' with 1 every touch
			num++;
		}
		
		return super.onTouchEvent(event);
	}
}
GameLoopThread.java

Code: Select all

package com.example.crashtest;

import android.annotation.SuppressLint;
import android.graphics.Canvas;

public class GameLoopThread extends Thread {
	  static final long FPS = 10;
       private GameView view;
       public boolean running = false;
       public boolean pause = false;
       
       public GameLoopThread(GameView view) {
             this.view = view;
       }
       
       public void setRunning(boolean run) {
             running = run;
       }
       
       @SuppressLint("WrongCall")
       @Override
       public void run() {
    	   long ticksPS = 1000 / FPS;
           long startTime = 0;
           long sleepTime = 0;
           
             while (running) {
                    Canvas c = null;
                    startTime = System.currentTimeMillis();
                    
                    try {
                           c = view.getHolder().lockCanvas();
                           synchronized (view.getHolder()) {
                        	   view.onDraw(c);
                           }
                    } finally {
                           if (c != null) {
                                  view.getHolder().unlockCanvasAndPost(c);
                           }
                    }
                    
                    sleepTime = ticksPS-(System.currentTimeMillis() - startTime);
                    try {
                           if (sleepTime > 0)
                                  sleep(sleepTime);
                           else
                                  sleep(10);
                    } catch (Exception e) {}
             }
       }
}

Re: My Android app crashes at exit (and screen rotation)

Posted: Sun Feb 02, 2014 6:16 pm
by superLED
I posted the same question at stackoverflow.com, and got an answer pretty quick. Here's the answer that solved my problem:

Look what you need when you close the Activity you need to stop your thread from my code implemented before see it :

Code: Select all

GameView gameView ;
 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        gameView = new GameView(this); 
        setContentView(gameView);
    }

 @Override
protected void onPause() {
    // TODO Auto-generated method stub
    super.onPause();
    gameView.StopView();

}
and you need to implement method called StopView() in your GameView like this

Code: Select all

 public void StopView() {

    if (gameLoopThread != null) {
        gameLoopThread.setRunning(false);

    }
}
the problem because you still call the run method in thread after you try to block the thread and so you need to stop it before to block it using join.

Re: [Solved]My Android app crashes at exit (and screen rotat

Posted: Mon Feb 03, 2014 7:56 am
by 0x0000000
Good to hear you solved it!

Looking forward to this game of yours.
Send me a link so I can check it out, thanks!

Re: [Solved]My Android app crashes at exit (and screen rotat

Posted: Tue Feb 04, 2014 5:49 pm
by superLED
0x0000000 wrote:Good to hear you solved it!

Looking forward to this game of yours.
Send me a link so I can check it out, thanks!
Check out This post to download, and read further about this project of mine :D
I would be really grateful if you'd give it a try ^^