I have a thread that running into an activity. I don't want that the thread continuos running when the user click the home button or, for example, the user receive a call phone.
So I want pause the thread and resume it when the user re-opens the application.
I've tried with this:
protected void onPause() {
synchronized (thread) {
try {
thread.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
super.onPause();
}
protected void onResume() {
thread.notify();
super.onResume();
}
It stops the thread but don't resume it, the thread seems freezed.
I've also tried with the deprecated method Thread.suspend() and Thread.resume(), but in this case into Activity.onPause() the thread doesn't stop.
Anyone know the solution?
Use wait() and notifyAll() properly using a lock.
Sample code:
class YourRunnable implements Runnable {
private Object mPauseLock;
private boolean mPaused;
private boolean mFinished;
public YourRunnable() {
mPauseLock = new Object();
mPaused = false;
mFinished = false;
}
public void run() {
while (!mFinished) {
// Do stuff.
synchronized (mPauseLock) {
while (mPaused) {
try {
mPauseLock.wait();
} catch (InterruptedException e) {
}
}
}
}
}
/**
* Call this on pause.
*/
public void onPause() {
synchronized (mPauseLock) {
mPaused = true;
}
}
/**
* Call this on resume.
*/
public void onResume() {
synchronized (mPauseLock) {
mPaused = false;
mPauseLock.notifyAll();
}
}
}
Try the below code it will work
Thread thread=null;
OnResume()
public void onResume(){
super.onResume();
if(thread == null){
thread = new Thread()
{
#Override
public void run() {
try {
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
thread.start();
}
}
onPause()
#Override
public void onPause(){
super.onPause();
if(thread != null){
Thread moribund = thread;
thread = null;
moribund.interrupt();
}
}
Related
I'm making a game for android and i'm running into some problems with my thread when I exit my game and restart it again. I'm trying to interrupt the thread in the onPause function in MainActivity and resuming the thread in the start function in gamepanel with notify. It sometime works but it's not really pausing the game.
What is the proper way to implement the activity lifecycle while pausing a thread? Especially a game thread where game update functions shouldn't be called while the user is away.
public class MainActivity extends Activity {
private GamePanel gamepanel;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
//removes title
requestWindowFeature(Window.FEATURE_NO_TITLE);
//full screen
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
gamepanel = new GamePanel(this);
setContentView(gamepanel);
SoundHandler.setContext(this);
}
#Override
protected void onPause() {
super.onPause();
gamepanel.getThread().interrupt();
}
#Override
protected void onStop() {
super.onStop();
}
#Override
protected void onRestart() {
super.onRestart();
}
#Override
protected void onResume() {
super.onResume();
}
#Override
protected void onDestroy() {
super.onDestroy();
boolean retry = true;
while (retry) {
try {
gamepanel.getThread().setRunning(false);
gamepanel.getThread().join();
} catch (InterruptedException e) {
e.printStackTrace();
}
retry = false;
}
}
}
Gamepanel that extends surfaceView:
#Override
public void surfaceDestroyed (SurfaceHolder holder){}
/**create surface.
*
* #param holder
*/
#Override
public void surfaceCreated (SurfaceHolder holder){
//we can safely start the game loop
System.out.println("CREATING SURFACE");
loadingscreen = false;
start();
}
public void start() {
if(!mGameIsRunning) {
thread.start();
thread.setRunning(true);
mGameIsRunning = true;
} else {
thread.onResume();
}
}
Thread class
public class MainThread extends Thread {
private SurfaceHolder surfaceHolder;
private GamePanel gamePanel;
public boolean running = false;
public static Canvas canvas;
private long startTime;
private long fps = 1/30;
public MainThread(SurfaceHolder surfaceHolder, GamePanel gamePanel) {
super();
this.surfaceHolder = surfaceHolder;
this.gamePanel = gamePanel;
startTime = System.nanoTime();
}
#Override
public void run()
{
while(running) {
if((System.nanoTime() - startTime) / 1000000000> fps) {
canvas = null;
//try locking the canvas for pixel editing
try {
canvas = surfaceHolder.lockCanvas();
synchronized (surfaceHolder) {
this.gamePanel.update();
this.gamePanel.draw(canvas);
this.gamePanel.checkSpeed();
}
} catch (Exception e) {
} finally {
if (canvas != null) {
try {
surfaceHolder.unlockCanvasAndPost(canvas);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
gamePanel.surfaceDestroyed(surfaceHolder);
}
public void onResume(){
synchronized(this){
this.notify();
}
}
public void setRunning(boolean b)
{
running=b;
}
public boolean getRunning(){
return running;
}
}
There is no memory barrier around boolean running you can synchronize or use private volatile boolean running;. Then you need to call setRunning(false) somewhere to stop it, which you do not seem to do. These reasons are probably why your thread isn't quitting.
But I don't believe it makes any sense to render the game in a separate thread anyway. If you can't update & render super fast anyway, (e.g. 1/60th second or better) then moving it to a thread isn't going to help.
Sir Please help me to add a thread that starts on a button click and ends the thread with another button click. In between I have a sound playing till the thread stops.
You can try this simple code:
final volatile boolean toExit = false;
final Thread t = new Thread(new Runnable() {
#Override
public void run() {
while(!toExit){
// Your code
Thread.sleep(100);
}
}
});
findViewById(R.id.button1).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
t.start();
}
});
findViewById(R.id.button2).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
toExit = true;
}
});
The thread will stop after button2 clicked and run to while(!toExit).
Threads stop method is deprecated.
The best solution will be having a boolean variable in the run method.
Your Thread:
public class MyThread implements Runnable {
private static final Logger LOGGER = LoggerFactory.getLogger(IndexProcessor.class);
private volatile boolean running = true;
public void terminate() {
running = false;
}
#Override
public void run() {
while (running) {
try {
//Your code that needs to be run multiple times
LOGGER.debug("Processing");
} catch (InterruptedException e) {
LOGGER.error("Exception", e);
running = false;
}
}
}
}
In your Activity:
MyThread t=new Thread();
findViewById(R.id.button1).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
t.start();
}
});
findViewById(R.id.button2).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
t.terminate();
}
});
Use Below Code
public class SomeBackgroundProcess implements Runnable {
Thread backgroundThread;
public void start() {
if( backgroundThread == null ) {
backgroundThread = new Thread( this );
backgroundThread.start();
}
}
public void stop() {
if( backgroundThread != null ) {
backgroundThread.interrupt();
}
}
public void run() {
try {
Log.i("Thread starting.");
while( !backgroundThread.interrupted() ) {
doSomething();
}
Log.i("Thread stopping.");
} catch( InterruptedException ex ) {
// important you respond to the InterruptedException and stop processing
// when its thrown! Notice this is outside the while loop.
Log.i("Thread shutting down as it was requested to stop.");
} finally {
backgroundThread = null;
}
}
Hope this will help you
Even if I press the back button, my timer is still running and the next activity is executed after the specified time. How do I stop this?
Splash.java :
package com.ultimate.biggboss;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.widget.VideoView;
public class Splash extends Activity{
VideoView vid;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.splash);
vid = (VideoView)findViewById(R.id.video);
String urlpath="android.resource://" + getPackageName() + "/" + R.raw.logoanimate;
vid.setVideoURI(Uri.parse(urlpath));
vid.start();
Thread timer = new Thread(){
public void run(){
try{
sleep(4400);
} catch (InterruptedException e){
e.printStackTrace();
}finally{
Intent openHome = new Intent(Splash.this, main.class);
startActivity(openHome);
finish();
}
}
};
timer.start();
}
}
What code do I write and where in this class to stop the app as soon as I press the back button?
you can handle the back key press in the following way:
#Override
public void onBackPressed() {
// your code.
}
and before API 5 use this:
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
// your code
}
return super.onKeyDown(keyCode, event);
}
Inside this, you can do something like:
if(null != timer){
timer.cancel();
}
Note that the Thread's stop(), suspend() etc., methods have been
deprecated, the only way to safely terminate a thread is to have it
exit its run() method.
Try following:
public class MyThread extends Thread {
private long sleepTime;
private boolean stop;
public MyThread(long sleepTime) {
this.sleepTime = sleepTime;
stop = false;
}
public void run() {
do {
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
} while (!stop);
}
// soft stopping of thread
public synchronized void stopThread() {
stop = true;
}
}
To start the thread:
MyThread timer = new MyThread(4400);
timer.start();
To stop the thread:
timer.stopThread();
So you can handle it on pressing back button like:
#Override
public void onBackPressed() {
if(timer != null){
timer.stopThread();
timer = null;
}
}
You should interrupt the Thread
public void onBackPressed()
{
timer.interrupt();
this.finish();
}
I think you can use a flag to stop a thread, below is how i had done it:
public static int flag=0;//whenever flag=1, stop the thread. Flag should be a static global variable
#Override
public void onBackPressed() {
flag=1;
}
//My thread code was somewhat like this:
Thread timer = new Thread(){
public void run(){
try{
while(1)
{
if(flag==0)
//My code here
else
stopThread(this);
}
} catch (InterruptedException e){
e.printStackTrace();
}
}
};
timer.start();
The code for stopThread() is given below:
private synchronized void stopThread(Thread theThread)
{
if (theThread != null)
{
theThread = null;
}
}
This code worked for me. Hope it helps you too.
I currently have an app which when a button is pressed starts a service and within the service a thread is created.
I then have a second button (which appears once the first it pressed) that should shut down the service and in turn kill the thread, below is my current code however the service seems to stop but the thread keeps going.
public class MainActivity extends Activity {
private static Button lock = null;
private static Button unlock = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lock = (Button) this.findViewById(R.id.lock);
unlock = (Button) this.findViewById(R.id.unlock);
lock.setOnClickListener(btn_lock);
unlock.setOnClickListener(btn_unlock);
unlock.setVisibility(View.VISIBLE);
lock.setVisibility(View.GONE);
text.setVisibility(View.GONE);
startService(new Intent(this, MainService.class));
}
private OnClickListener btn_lock = new OnClickListener() {
public void onClick(View v) {
unlock.setVisibility(View.VISIBLE);
lock.setVisibility(View.GONE);
startService(new Intent(MainActivity.this, MainService.class));
}
};
private OnClickListener btn_unlock = new OnClickListener() {
public void onClick(View v) {
unlock.setVisibility(View.GONE);
lock.setVisibility(View.VISIBLE);
stopService(new Intent(MainActivity.this, MainService.class));
}
};
}
And then my service class looks like:
public class MainService extends Service {
Thread 1Thread;
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public void onCreate() {
1Thread = new Thread() {
public void run() {
while(true){
try {
Thread.sleep(180000); // 3 minutes
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.i("TEST", "Thread is still here!");
}
}
};
}
#Override
public void onDestroy() {
1Thread.interrupt();
}
#Override
public void onStart(Intent intent, int startId) {
1Thread.start();
}
}
Hope someone can help and if you need any more info let me know!
boolean mStatus = true;
#Override
public void onCreate() {
1Thread = new Thread() {
public void run() {
while (mStatus) {
try {
Thread.sleep(180000); // 3 minutes
} catch (InterruptedException e) {
e.printStackTrace();
continue;
}
Log.i("TEST", "Thread is still here!");
}
};
}
#Override
public void onDestroy() {
mStatus = false;
1Thread.interrupt();
}
Your thread is not handling interrupt, in while loop in each iteration check if thread is interrupted, if so then do not continue the loop:
while(!Thread.currentThread().isInterrupted()){
try {
Thread.sleep(180000); // 3 minutes
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
break; //BREAK here, as thread was interrupted
}
Log.i("TEST", "Thread is still here!");
}
Also on click of second button, you should interrupt this thread:
1Thread.interrupt();
My code here works fine . It changes the image in my gallery at certain times , but i dont think this is the best approach , especially using thread.sleep() . How can i write a better code for that ? What am i missing ?
Thanks..
#Override
protected void onResume() {
paraThread = true;
workThread = new LooperFoto("MyWorkThread");
workThread.setPriority(Thread.MIN_PRIORITY);
workThread.start();
super.onResume();
}
#Override
protected void onStop() {
Log.i(TAG, "thread state: " + workThread.getState());
paraThread = false;
workThread = null;
super.onStop();
}
class LooperFoto extends HandlerThread {
public LooperFoto(String name) {
super(name);
}
#Override
public void run() {
while (paraThread) {
try {
this.sleep(2000);
mudaFoto.sendMessage(new Message());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Handler mudaFoto = new Handler() {
public void handleMessage(Message msg) {
Random generator = new Random();
int randomIndex = generator.nextInt(thumbImgGallery.getAdapter()
.getCount());
thumbImgGallery.setSelection(randomIndex);
};
};
As long as the thread that is .sleeping() is not your main (UI) thread, you should be fine. What are you worried about?