I am able to pause/resume my game by making my game thread(which holds/synchronized with surfaceview) wait/notifyAll. This all runs well using the in game pause button.
However, when I click home/back button I am able to pause my game, but when I resumes my game by clicking on its icon, I receive non responsive game screen back to me.
I have put logs on OnResume() method but nothing gets printed in LogCat!
If I click on my game screen I get error dialog to "Force Close" or "Wait" on my game activity.
Why I am getting this non responsive screen as if my application Hangged after pause ?
How can I handle physical buttons in same way as inGame pause/resume button ?
here is my logcat view of the operation. you can see onResume sop not getting printed similar to onPause.
EDIT : Code called by my pause/resume button and by onPause/onResume functions
where "this" is thread class itself
protected void setPause(){
synchronized (this) {
isPaused = true;
}
}
protected void setResume(){
synchronized (this) {
isPaused = false;
this.notifyAll();
}
}
Game Loop Code :
synchronized (this) {
while (running) {
if (isPaused) {
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
Canvas c = null;
try {
c = view.getHolder().lockCanvas();
synchronized (view.getHolder()) {
view.onDraw(c);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} 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) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
This how I am calling it from surface view :
public void surfaceCreated(SurfaceHolder holder) {
// start the game loop
System.out.println("Starting Game Loop #########");
if(isPaused){
System.out.println("GamePaused");
gameLoopThread.setResume();
}
else{
System.out.println("Game Starting");
gameLoopThread.setRunning(true);
}
gameLoopThread.start();
}
EDIT 2:
If I Pause my game using pause button and let my phone get locked automatically... after resuming I am able to play normally with out any issue.
As per logs I see surface destroyed is not getting called in this case.
After onResume, your SurfaceView is created again, but it lost all the data it had before (all info needed for onDraw). you have to save the data in surfaceDestroyed or before, and reload it in the onCreate of your surfaceview
Related
Please check this link. Following code is from this link. I am not sure why it says we have to use thread sleep to limit number of touch events.
I have a surfaceview and gamethread which processes events pushed by touch event. Is this sleep required or should I handle the sleep in gamethread instead by controlling framerate.
try {
Thread.sleep(16);
} catch (InterruptedException e) {
}
return true;
}
whole code
#Override
public boolean onTouchEvent(MotionEvent event) {
// we only care about down actions in this game.
try {
// history first
int hist = event.getHistorySize();
if (hist > 0) {
// add from oldest to newest
for (int i = 0; i < hist; i++) {
InputObject input = inputObjectPool.take();
input.useEventHistory(event, i);
gameThread.feedInput(input);
}
}
// current last
InputObject input = inputObjectPool.take();
input.useEvent(event);
gameThread.feedInput(input);
} catch (InterruptedException e) {
}
// don't allow more than 60 motion events per second
try {
Thread.sleep(16);
} catch (InterruptedException e) {
}
return true;
}
Your link points to an article that has been posted in 2009, you should really try to find one that is more up to date.
The code itself looks wrong, the author explains that his code is designed to avoid blocking the UI thread but then calls Thread.sleep(16) in onTouchEvent() which is called from the UI thread and blocks it.
What about this example? I haven't read it in detail, but the code looks much better : https://www.codeproject.com/Articles/827608/Android-Basic-Game-Loop
I have this code to turn camera flash on and off in android:
params = camera.getParameters();
params.setFlashMode(Parameters.FLASH_MODE_TORCH);
camera.setParameters(params);
camera.startPreview();
isFlashOn = true;
The problem appear if flash is on and user turn off screen. flash automatically turned off and return on when screen is on.
I need to keep flash on when screen off.
Any idea please?
Here is a link to the problem you're having. "The key is changing the state back to FLASH_MODE_OFF and then back to FLASH_MODE_TORCH."
In the solution, he creates a Timer Task to handle checking if the screen is on or not. He then turns off the flash and then back on.
Down below the linked solution is another solution which added a thread and made it go to sleep for 200 milliseconds before sending the torch command.
So I'd say the solution you're looking for is the combination of both solutions.
#Override
public void onCreate() {
// assume we start with screen on and save that state ;-)
this.pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
screenOn = this.pm.isScreenOn();
// program a timer which checks if the light needs to be re-activated
this.mTimer = new Timer();
this.mTimerTask = new TimerTask() {
public void run() {
// re-activate the LED if screen turned off
if(!pm.isScreenOn() && pm.isScreenOn() != screenOn) {
Log.i("SleepLEDservice", "re-activated the LED");
// really it's NOT ENOUGH to just "turn it on", i double-checked this
setFlashlight(Camera.Parameters.FLASH_MODE_OFF);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
setFlashlight(Camera.Parameters.FLASH_MODE_TORCH);
}
screenOn = pm.isScreenOn();
}
};
}
private void setFlashlight(String newMode) {
try {
this.frontCamPara = this.frontCam.getParameters();
if(this.frontCamPara.getFlashMode() != newMode) {
this.frontCamPara.setFlashMode(newMode);
this.frontCam.setParameters(frontCamPara);
}
} catch (Exception e) {
e.printStackTrace();
}
}
Again, credit should go to #stefanjunker and #BlueJam as their answers are referenced in this.
I am developing app and I need that my app will be doing two actions at the same time. For example - I can drag marker and the map will be scrolling at the same time.
I tried to update map while dragging marker, everything would be okay, except thing that when thread starts, maps starts scrolling continuously and I cand do anything more. Here is the code, I call it in onCreate() method. I tried to do Runnable and AsyncTask and the results were the same. Any suggestions?
private void update() {
new Thread() {
public void run() {
while (true) {
runOnUiThread(new Runnable() {
#Override
public void run() {
while (drag)
mMap.animateCamera(CameraUpdateFactory.scrollBy(10, 0), 2, null);
}
});
try {
Thread.sleep(2);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}.start();
}
You don't have the code to interrupt your thread. That's why your map keep scrolling. Try to use drag event to drive this animation, and add some code to terminate the thread at some point.
Edit: I found out the problem is in the onPreviewFrame function:
#Override
public void onPreviewFrame(byte[] data, Camera camera) {
if (frameCount == 0) {
start = System.currentTimeMillis();
} else if (frameCount % 100 == 0) {
Log.e("FPS", 1000 * frameCount
/ (System.currentTimeMillis() - start) + "");
}
frameCount++;
Bitmap temp = BitmapFactory.decodeByteArray(data, 0, data.length);
try {
temp.compress(CompressFormat.JPEG, 90, new FileOutputStream(new File("/sdcard/"+frameCount+".jpg")));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
camera.addCallbackBuffer(data);
}
If I remove all the code related to Bitmap then the program can take a picture without any error. How can I save both frame images and the better image produced with Camera.takePicture?
I tried to save photo from camera when a button is touched and start another activity to edit the photo.
mTakePic.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
mTakePic.setImageDrawable(takePicDown);
mCamera.takePicture(new ShutterCallback() {
#Override
public void onShutter() {
// TODO Auto-generated method stub
}
}, null, new PictureCallback() {
#Override
public void onPictureTaken(byte[] yuv, Camera camera) {
Intent editImage = new Intent(getApplicationContext(), EditActivity.class);
if(savePhoto != null) {
try {
savePhoto.get();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
savePhoto = new SavePhotoTask();
savePhoto.execute(yuv);
// releaseCamera();
startActivity(editImage);
}
});
} else if (event.getAction() == MotionEvent.ACTION_UP) {
mTakePic.setImageDrawable(takePicUp);
}
return true;
}
});
Sometimes it runs smoothly without error but most times it ends up an error and I have to restart my phone to get the camera working again. I used a SurfaceView for previewing camera frame.
Edit: Sorry, I mistook the question, I thought you were linking the crash you mentioned to the SavePhotoTask. Here's how you can save a photo from your PictureCallback
The first argument to onPictureTaken is a byte array that contains the image. Simply writing it out to a file is the best way I've found to save the image. Something like this...
FileOutputStream out = new FileOutputStream("path/to/image");
out.write(data, 0, data.length);
out.close();
Where "data" is the first arg from onPictureTaken. This same technique should work to save each frame in onPreviewFrame but I've never tried this so I can't be sure. It seems like you have the idea of putting this operation on a separate thread, which is excellent and I'd continue exploring that option. I'd avoid using a Bitmap however, as this will take time and resources, and could lead to OOM errors if you're converting many frames concurrently and have all those Bitmaps in memory.
Once you make the call to Camera.open(), your app is putting a lock on the camera and blocking any other applications (including subsequent instances of your own application) from using it. A call must be made to Camera.release() when your application is done or the camera will remain locked until, as you've noted, the phone is restarted. The dev docs for the Camera has a good checklist to follow at the top in order to ensure the class gets used correctly.
I've had success making the call to Camera.open() in onResume() and Camera.release() in onPause(). To keep things smooth and bug free, you may want to manage your start and stop preview at these points as well.
I am building a 2D game with Android SurfaceView. When I touch the screen the game animation runs slowly. Why, and how can I avoid this?
The touch events are stubs just like onTouchEvents(MotionEvents ev){ empty };. All of the game logic and graphics draw code are in run() in an extends Thread class.
Sleeping the UI thread for 16-20ms will keep the touch event handling code from being called too many times per second.
Example:
#Override
public boolean onTouchEvent(MotionEvent event) {
//Event handling logic
try {
Thread.sleep(16);
} catch (InterruptedException e) {
e.printStackTrace();
}
return true;
}
Touch events are dispatched as quickly as the UI thread can read them, by sleeping the thread you are able to skip a number of event dispatches. (Though not a noticeable amount for your game logic or the user)
Have you looked at the tutorials at http://www.droidnova.com ? They are good intro game tuts and ran very quickly when I did them. If they run slowly on your device with touch it is probably not a dev issue
#Override
public void run ( )
{
while(irunning)
{
while(paused)
{
sleep(2);
synchronized ( holder )
{
canvas = holder.lockCanvas(null);
//updateEvents();
//updatePsgstate();
//updateRole();
sortImages();
drawBgland();
drawImages();
drawAdminicle();
holder.unlockCanvasAndPost(canvas);
}
}
sleep(10);
}
}
#Override
public boolean dispatchTouchEvent ( MotionEvent ev )
{
try
{
Thread.sleep( 32 );
}
catch ( InterruptedException e )
{
e.printStackTrace();
}
synchronized ( ev )
{
Log.i( "T" , "onTouch" );
}
return true;
}
#Override
public void surfaceCreated(SurfaceHolder holder)
{
mThread.start();
// if (hasFocus())
// {
// return;
// }
// else
// {
// requestFocusFromTouch();
// }
}
this is base method that i used.
that's my code. any problem about it ?