I am working on an android game.I was the facing the same issue as here
I tried the wait and notify all solution as shown over there.But as soon the app resumes i get Null pointer exception.
Here is the log cat info.
INFO/System.out(8166): on resume
INFO/System.out(8166): !!!! IN THE GAME RESUME ---- >>>
INFO/System.out(8166): SURFACE CREATED
INFO/System.out(8166): thread on resume
INFO/System.out(8166): in thread game pause=true
WARN/dalvikvm(8166): threadid=7: thread exiting with uncaught exception (group=0x4001d800)
ERROR/AndroidRuntime(8166): FATAL EXCEPTION: Thread-11
ERROR/AndroidRuntime(8166): java.lang.NullPointerException
ERROR/AndroidRuntime(8166): at com.org.GummyBlast.GameView.onDraw(GameView.java:442)
ERROR/AndroidRuntime(8166): at com.org.GummyBlast.GameLoopThread.run(GameLoopThread.java:88)
The code inside onSurfaceCreated and onSurfaceDestroyed
private void init() {
gameLoopThread = new GameLoopThread(this);
holder = getHolder();
holder.addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
System.out.println(" SURFACE DESTROYED");
nullImages();
boolean retry = true;
//gameLoopThread.setRunning(false);
if(!mGameIsRunning){
while (retry) {
try {
gameLoopThread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
System.out.println(" SURFACE CREATED");
Log.d("surface create", "SURFACE CREATED");
/*gameLoopThread.setRunning(true);
gameLoopThread.start();*/
start(holder);
}
public void start(SurfaceHolder holder) {
if (!mGameIsRunning) {
gameLoopThread.setRunning(true);
gameLoopThread.start();
mGameIsRunning = true;
} else {
gameLoopThread.onResume();
}
}
Code in my GameThread class
public class GameLoopThread extends Thread {
static final long FPS = 10;
private GameView view;
public static boolean running = false;
public static boolean run = true;
public static boolean game_pause=true;
private static Object mPauseLock;
private boolean mFinished=false;
long ticksPS = 1000 / FPS;
long startTime;
long sleepTime;
SurfaceHolder holder;
public GameLoopThread(GameView view) {
mPauseLock = new Object();
this.view = view;
}
public GameLoopThread() {
mPauseLock = new Object();
}
public void setRunning(boolean run) {
running = run;
}
#Override
public void run() {
while (running) {
// Do stuff.
System.out.println("in thread game pause="+Boolean.toString(game_pause));
if (game_pause == true) {
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) {
System.out.println("Error in game loop thread "+ e.getMessage());
}
}
else{
synchronized (mPauseLock) {
while (game_pause==false) {
try {
mPauseLock.wait();
} catch (InterruptedException e) {
}
}
}
}
}
}
public void onPause() {
synchronized (mPauseLock) {
game_pause = false;
System.out.println("thread on pause");
}
}
/**
* Call this on resume.
*/
public void onResume() {
synchronized (mPauseLock) {
game_pause = true;
mPauseLock.notifyAll();
System.out.println("thread on resume");
}
}
}
Activity class onPause
#Override
public void onPause() {
super.onPause();
System.out.println(" --- IN GAME PAUSE ---");
gameLoopThread = new GameLoopThread();
gameLoopThread.onPause();
}
how to maintain the state of the game in onResume?
Thanks
Maybe you need to call onResume() on your superclass:
public void onResume() {
super.onResume();
}
Hope this helps you.
Related
how should I deal with the game loop when the user switches from my Android game to something else and then back?
Stopping and recreating the thread
Pausing/continuing the thread using wait() and notify()
Option #1 would look like this:
public void run() {
while (isRunning) {
// do stuff
}
}
#Override
protected void onPause() {
boolean retry = true;
gameLoop.setRunning(false);
while (retry) {
try {
mainThread.join();
retry = false;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
super.onPause();
}
#Override
protected void onResume() {
if (gameLoop.isRunning()) {
stop();
}
gameLoop.setRunning(true);
mainThread = new Thread(gameLoop);
mainThread.start();
super.onResume();
}
Option #2 would look like this:
public void run() {
while (!mFinished) {
// do stuff
synchronized (mPauseLock) {
while (mPaused) {
try {
mPauseLock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
#Override
protected void onPause() {
synchronized (mPauseLock) {
mPaused = true;
}
super.onPause();
}
#Override
protected void onResume() {
synchronized (mPauseLock) {
mPaused = false;
mPauseLock.notifyAll();
}
super.onResume();
}
Which option is the better one? And also should I use onPause()/onResume() or onStop()/onStart() to do these thread operations?
Thank you!
there Folks! And Here it goes another Question.. from me..
I'm making a flashlight app. In the app there are two buttons, one is for turning on/off flash (flashlight_switch) and the other one is for blinking the flash With a single tap on the Button (sos_switch) at medium speed. The flash on/off works perfectly, but when i press the SOS button the app freezes and crashes. And also how can I turn off the SOS. I'm a beginner so it would be very nice that you explain the answer in depth. Please ignore Any typos if there are. The App is tested on Galaxy S3 and LG G3 and no luck on both of them.
Here is the complete code:
Java:
FlashlightActivity:
public class FlashlightActivity extends Activity {
ImageButton flashlight_switch;
ImageButton sos_switch;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_flashlight);
flashlight_switch = (ImageButton) findViewById(R.id.flashlight_switch);
sos_switch = (ImageButton) findViewById(R.id.sos_switch);
flashlight_switch.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
view.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
if (Flash.getTorch()) {
flashlight_switch.setImageResource(R.drawable.flashlight_switch_on);
} else {
flashlight_switch.setImageResource(R.drawable.flashlight_switch_off);
}
}
});
sos_switch.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (SOS.getSOS()) {
sos_switch.setImageResource(R.drawable.sos_on);
} else {
sos_switch.setImageResource(R.drawable.sos_off);
}
}
});
}
}
Flash:
class Flash {
private static boolean flashOnOff = false;
private static boolean sosOnOff = false;
public static Camera camera;
private static Camera.Parameters params;
public static boolean getTorch() {
if (flashOnOff)
off();
else
on();
return flashOnOff;
}
public static boolean getSOS() {
if (sosOnOff)
offSOS();
else
onSOS();
return sosOnOff;
}
private static void on() {
if (!flashOnOff) {
if (camera == null || params == null) {
try {
camera = Camera.open();
params = camera.getParameters();
} catch (RuntimeException e) {
int a = 10;
}
}
try {
camera.setPreviewTexture(new SurfaceTexture(0));
params = camera.getParameters();
params.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
camera.setParameters(params);
camera.startPreview();
flashOnOff = true;
} catch (Exception e) {
e.printStackTrace();
}
}
}
private static void off() {
if (camera == null || params == null)
return;
params = camera.getParameters();
params.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
camera.setParameters(params);
camera.stopPreview();
camera.release();
camera = null;
flashOnOff = false;
}
private static void onSOS() {
Thread t = new Thread() {
public void run() {
try {
int delay = 50;
int times = 10;
for (int i=0; i < times*2; i++) {
if (flashOnOff) {
on();
} else {
off();
}
sleep(delay);
}
} catch (Exception e){
e.printStackTrace();
}
}
};
t.start();
}
private static void offSOS() {
Thread t = new Thread();
t.stop();}}
Thanks In Advance!
Update:
I have updated my flash.java. It does not crash now but still the SOS don't work and also the sos switch freezes. I can't figure it out now. Please help!!!! as soon as possible!
You should not sleep Thread.sleep(blinkDelay); the thread because it is main thread need to update UI.you should use a different thread for SOS on
And Your SOS on function is in recursive infinite loop plz edit it. You are calling ON infinite time recursivly
Make Flash class ON / OFF method to public and make few changes in SOS's on method on(); to Flash.on and off to Flash .off
Flash.java
class Flash {
private static boolean flashOnOff = false;
public static Camera camera;
private static Camera.Parameters params;
static Thread t;
public static boolean getTorch() {
if (flashOnOff) // turn off flash
off();
else // turn on flash
on();
return flashOnOff;
}
private static void on() {
if (!flashOnOff) {
if (camera == null || params == null) {
try {
camera = Camera.open();
params = camera.getParameters();
} catch (RuntimeException e) {
int a = 10;
}
}
try {
params = camera.getParameters();
params.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
camera.setParameters(params);
camera.setPreviewTexture(new SurfaceTexture(0));
camera.startPreview();
flashOnOff = true;
} catch (Exception e) {
e.printStackTrace();
}
}
}
private static void off() {
if (camera == null || params == null)
return;
params = camera.getParameters();
params.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
camera.setParameters(params);
camera.stopPreview();
flashOnOff = false;
}
public static void onSOS() {
t = new Thread() {
public void run() {
try {
int delay = 50;
while (true) {
if (t.isInterrupted())
break;
getTorch();
sleep(delay);
}
} catch (Exception e) {
e.printStackTrace();
}
}
};
t.start();
}
public static void offSOS() {
if (!t.isInterrupted()) {
t.interrupt();
off();
}
}}
FlashlightActivity.java
public class FlashlightActivity extends Activity {
ImageButton flashlight_switch;
ImageButton sos_switch;
boolean isStart = false;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_flashlight);
flashlight_switch = (ImageButton) findViewById(R.id.flashlight_switch);
sos_switch = (ImageButton) findViewById(R.id.sos_switch);
flashlight_switch.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
view.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
if (Flash.getTorch()) {
flashlight_switch.setImageResource(R.drawable.flashlight_switch_on);
} else {
flashlight_switch.setImageResource(R.drawable.flashlight_switch_off);
}
}
});
sos_switch.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (!isStart){
Flash.onSOS();
isStart = true;
sos_switch.setImageResource(R.drawable.sos_off);
}else{
Flash.offSOS();
isStart = false;
sos_switch.setImageResource(R.drawable.sos_on);
}
}
});
}
}
im trying to develop a game app.I implement onResume and onPause methods. onPause method works fine however onResume method crushes.
#Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
resume();
}
public void resume()
{
addAnime();
myThread.setRunning(true);
myThread.start();
}
if im not call update in onResume method myApp works fine but if i pause game and resume it again emulator says app not responding.
if i call resume in onResume method it says canvas is null at first runnig
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
view.resume();
}
I dont understand why canvas is null at the begining of the app when i call resume in onResume.Someone explain me?
EDIT
puase():
public void pause()
{
boolean repaet=true;
while(repaet)
{
try {
myThread.join();
myThread.setRunning(false);
repaet=false;
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
myThread=null;
}
EDIT2
myThread
public void run() {
long ticksPS = 1000 / FPS;
long startTime;
long sleepTime;
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) {}
}
EDIT3
here is my set runnig function
public void setRunning(boolean run) {
running = run;
}
Pause method:
public void pause()
{
boolean repeat = myThread != null;
while(repeat)
{
try {
myThread.setRunning(false);
myThread.join();
repeat=false;
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
myThread=null;
}
myThread:
public class gameThread extends Thread {
private SurfaceView view;
private boolean isRunning;
private static final int FPS; // set FPS with your value
private void sleep(long time) throws InterruptedException
{
Thread.sleep(time);
}
public void setRunning(boolean running)
{
synchronized(this)
{
this.isRunning = running;
}
}
public boolean isRunning()
{
synchronized(this)
{
return this.isRunning;
}
}
public void run()
{
long ticksPS = 1000 / FPS;
long startTime;
long sleepTime;
while (isRunning()) {
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) {}
}
}
Resume method:
public void resume()
{
addAnime();
// you must create a new thread. (You cannot use this same thread if it end)
myThread = new gameThread(surfaceView);
myThread.setRunning(true);
myThread.start();
}
Hi you can find further information in the documentation.
SurfaceHolder.lockCanvas
Start editing the pixels in the surface. The returned Canvas can be used to draw into the surface's bitmap. A null is returned if the surface has not been created or otherwise cannot be edited. You will usually need to implement Callback.surfaceCreated to find out when the Surface is available for use.
The content of the Surface is never preserved between unlockCanvas() and lockCanvas(), for this reason, every pixel within the Surface area must be written. The only exception to this rule is when a dirty rectangle is specified, in which case, non-dirty pixels will be preserved.
If you call this repeatedly when the Surface is not ready (before Callback.surfaceCreated or after Callback.surfaceDestroyed), your calls will be throttled to a slow rate in order to avoid consuming CPU.
about the use of Threads or Runneables, you can check this.
https://guides.codepath.com/android/Repeating-Periodic-Tasks
http://developer.android.com/guide/components/processes-and-threads.html
I actually can pause the thread correctly but when I press the unpause button
it doesn't resume. What am I doing wrong ?
public void pause() {
mRun = false;
while (true) {
try {
_thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
}
_thread = null;
}
public void unpause() {
mRun = true;
_thread = new GameBoardThread(this);
_thread.start();
}
i'm having a problem with restarting my game after clicking home or return button on android.
I've found partial solution in thread:
Android crash when app is closed and reopened, but the game after restarting dosen't work properly.
It only shows images/sprites which also moves, but dosen't read touches.
//this is in game view
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) { // ce se spremeni zaslon
}
public void surfaceCreated(SurfaceHolder holder) {
createSprites();
start();
}
public void start() {
loop.setRunning(true);
if (!mGameIsRunning) {
loop.start();
mGameIsRunning = true;
} else {
loop.onResume();
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
while (retry) {
try {
loop.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
//and this is game thread
while (running) {
canvas = null;
try{
canvas = this.surfaceHolder.lockCanvas();
synchronized (surfaceHolder) {
beginTime = System.currentTimeMillis();
framesSkipped = 0;
this.gameView.update();
this.gameView.render(canvas);
synchronized (mPauseLock) {
while (mPaused) {
try {
mPauseLock.wait();
} catch (InterruptedException e) {
}
}
}
timeDiff = System.currentTimeMillis() - beginTime;
sleepTime = (int)(FRAME_PERIOD - timeDiff);
if (sleepTime > 0){
try{
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
}
}
}
} finally {
if (canvas != null){
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
}
public void onPause() {
synchronized (mPauseLock) {
mPaused = true;
}
}
public void onResume() {
synchronized (mPauseLock) {
mPaused = false;
mPauseLock.notifyAll();
}
}
Can anyone tell me if there is any mistake or any other solution.
Thanks for help.
Or if anyone could tell me for a good way to stop game and restart it, please?
I fixed it so that it works when i hit home, but when i hit back and restart it, I get black screen.
// current gameview code
public void surfaceCreated(SurfaceHolder holder) {
if (loop==null)
loop = new GameLoop(getHolder(), this);
if(loop.getState() == Thread.State.TERMINATED)
{
loop = new GameLoop(getHolder(), this);
}
start();
}
public void start() {
if (!mGameIsRunning) {
mGameIsRunning = true;
loop.setRunning(true);
loop.start();
} else {
loop.onResume();
loop.start();
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
loop.onPause();
}
I have a feeling that the problem is in surfaceDestroy method, but I'm not sure since I don't know what is the difference between hitting home or back key.