I have tried some ways to do it and didn't secced.
I have MainActivity which start 3 thread. I want to stop the threads when the user press "back" bottum or when from some reason the app stop (phone call for example).
and after the activity again seen (when the user come back to the app) the thread will continue from where they stop.
All the threads defined in MainActivity and there they start.
Thanks!
public class MainActivity extends Activity
{
//threads
private PingPongGame gameThread;
private PaddleMover paddleMoverThread;
private PresentThread giftThread;
public GameSounds gameSounds;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState)
{
requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
gameLevel = new GameLevel0(screenWidth , screenHeight, this.giftArr);
gameLevelView = new GameLevelView(this,gameLevel);
// Creating the game view
this.gameView = new PingPongView(this);
// Setting the gameView as the main view for the PingPong activity.
setContentView(gameView);
if(gameThread == null){
//create the main thread
gameThread = new PingPongGame( gamePaddle, gameView, gameLevel , message , ballArr , gameSounds);
//create the thread responsible for moving the paddle
paddleMoverThread = new PaddleMover(gamePaddle, gameView);
//create the thread responsible for present
giftThread = new PresentThread(gamePaddle , gameView , gameLevel, message , giftArr , ballArr,gameSounds );
gameThread.start();
paddleMoverThread.start();
giftThread.start();
}
}
//This method is automatically called when the user touches the screen
#Override
public boolean onTouchEvent(MotionEvent event)
{
float destination;
// Toast.makeText(this, "try!", Toast.LENGTH_SHORT).show();
//get the x coordinate of users' press
destination = event.getX();
//notify the paddle mover thread regarding the new destination
gamePaddle.setPaddleDestination(destination);
return true;
}
}
Example of one of my threads:
public class PaddleMover extends Thread
{
private Tray gamePaddle; //holds a reference to the paddle
private PingPongView gameView; //holds a reference to the main view
//for stop
private Object mPauseLock;
private boolean mPaused;
//initialize class variables
public PaddleMover(Tray thePaddle, PingPongView mainView)
{
gamePaddle = thePaddle;
gameView = mainView;
//for stop and resume threads
mPauseLock = new Object();
mPaused = false;
}
//main method of the current thread
#Override
public void run()
{
//infinitely loop, and move the paddle if necessary
while ((Const.isLose == false) && (Const.isCompleteThisLevel==false) && (Const.isDestroy == false))
{
//check whether the paddle should be moved
if (gamePaddle.getMiddle() != gamePaddle.getPaddleDestination())
{
//move the paddle
gamePaddle.move();
//send a request to refresh the display
gameView.postInvalidate();
}
try
{
PaddleMover.sleep(3);
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
//for stop and resume
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();
}
}
}
You can achieve a lot better control with your threads using Runnable objects. Instead of defining your logic using a loop within the run() method, do the following:
Define your framewise logic for each thread within Runnable objects. Override the run() method. Do not use a while loop within your Runnable.
Create a variable which tracks whether or not your game is paused. Use this variable to create a single while() loop within a main thread.
Define a Thread class and get it's Handler. You can do this like so:
class WorkerThread extends Thread
{
private volatile Handler mHandler;
//volatile so you can try to acquire it until it is instantiated
#Override
public void run()
{
//This is pretty much boilerplate for worker thread implementations
Looper.prepare();
//Handlers must be instantiated by their respective threads
mHandler = new Handler();
Looper.loop();
}
#Override
public Handler getHandler()
{
return mHandler;
}
}
Instantiate multiple WorkerThreads and acquire references to their Handler objects.
In each frame, pass the Runnable() which defines the logic you want the Thread to execute to the Handler using the postRunnable() method.
Use ConditionVariable objects to make sure you don't call the postRunnable() method while the WorkerThread is still executing.
Runnable thread1runnable = new Runnable()
{
#Override
public void run()
{
//Do your logic here
...
thread1finished.open(); //This lets the block() function return
}
}
ConditionVariable thread1finished = new ConditionVariable();
thread1finished.open(); //Make sure the loop doesn't block the first time through
Thread thread1 = new WorkerThread();
//Start the thread to acquire the handler and prepare it for looping
thread1.start();
//Call stop() when shutting down your game, not pausing
Handler thread1handler;
while (thread1handler != null)
thread1handler = thread1.getHandler();
//A crude way of making sure you acquire the instantiated handler, you can top this
while (gameRunning)
{
if (!isPaused) //Stops work when your isPaused variable is set
{
thread1finished.block(); //Wait for the last runnable to finish
//Lock the ConditionVariable so the loop will block
thread1finished.close();
//Signal the worker thread to start crunching
thread1handler.postRunnable(thread1runnable);
}
}
In your onPause() override, set the variable that stops your while() loop from posting the Runnable objects to your WorkerThreads. Enjoy automatic starting and stopping!
There may be issues adapting this method to three different threads which you don't want to synchronize frame-per-frame. Let me know how it goes.
Related
I want to make a pause between two lines of code, Let me explain a bit:
-> the user clicks a button (a card in fact) and I show it by changing the background of this button:
thisbutton.setBackgroundResource(R.drawable.icon);
-> after let's say 1 second, I need to go back to the previous state of the button by changing back its background:
thisbutton.setBackgroundResource(R.drawable.defaultcard);
-> I've tried to pause the thread between these two lines of code with:
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
However, this does not work. Maybe it's the process and not the Thread that I need to pause?
I've also tried (but it doesn't work):
new Reminder(5);
With this:
public class Reminder {
Timer timer;
public Reminder(int seconds) {
timer = new Timer();
timer.schedule(new RemindTask(), seconds*1000);
}
class RemindTask extends TimerTask {
public void run() {
System.out.format("Time's up!%n");
timer.cancel(); //Terminate the timer thread
}
}
}
How can I pause/sleep the thread or process?
One solution to this problem is to use the Handler.postDelayed() method. Some Google training materials suggest the same solution.
#Override
public void onClick(View v) {
my_button.setBackgroundResource(R.drawable.icon);
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
my_button.setBackgroundResource(R.drawable.defaultcard);
}
}, 2000);
}
However, some have pointed out that the solution above causes a memory leak because it uses a non-static inner and anonymous class which implicitly holds a reference to its outer class, the activity. This is a problem when the activity context is garbage collected.
A more complex solution that avoids the memory leak subclasses the Handler and Runnable with static inner classes inside the activity since static inner classes do not hold an implicit reference to their outer class:
private static class MyHandler extends Handler {}
private final MyHandler mHandler = new MyHandler();
public static class MyRunnable implements Runnable {
private final WeakReference<Activity> mActivity;
public MyRunnable(Activity activity) {
mActivity = new WeakReference<>(activity);
}
#Override
public void run() {
Activity activity = mActivity.get();
if (activity != null) {
Button btn = (Button) activity.findViewById(R.id.button);
btn.setBackgroundResource(R.drawable.defaultcard);
}
}
}
private MyRunnable mRunnable = new MyRunnable(this);
public void onClick(View view) {
my_button.setBackgroundResource(R.drawable.icon);
// Execute the Runnable in 2 seconds
mHandler.postDelayed(mRunnable, 2000);
}
Note that the Runnable uses a WeakReference to the Activity, which is necessary in a static class that needs access to the UI.
You can try this one it is short
SystemClock.sleep(7000);
WARNING: Never, ever, do this on a UI thread.
Use this to sleep eg. background thread.
Full solution for your problem will be:
This is available API 1
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(final View button) {
button.setBackgroundResource(R.drawable.avatar_dead);
final long changeTime = 1000L;
button.postDelayed(new Runnable() {
#Override
public void run() {
button.setBackgroundResource(R.drawable.avatar_small);
}
}, changeTime);
}
});
Without creating tmp Handler. Also this solution is better than #tronman because we do not retain view by Handler.
Also we don't have problem with Handler created at bad thread ;)
Documentation
public static void sleep (long ms)
Added in API level 1
Waits a given number of milliseconds (of uptimeMillis) before returning. Similar to sleep(long), but does not throw InterruptedException; interrupt() events are deferred until the
next interruptible operation.
Does not return until at least the specified number of milliseconds has elapsed.
Parameters
ms to sleep before returning, in milliseconds of uptime.
Code for postDelayed from View class:
/**
* <p>Causes the Runnable to be added to the message queue, to be run
* after the specified amount of time elapses.
* The runnable will be run on the user interface thread.</p>
*
* #param action The Runnable that will be executed.
* #param delayMillis The delay (in milliseconds) until the Runnable
* will be executed.
*
* #return true if the Runnable was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting. Note that a
* result of true does not mean the Runnable will be processed --
* if the looper is quit before the delivery time of the message
* occurs then the message will be dropped.
*
* #see #post
* #see #removeCallbacks
*/
public boolean postDelayed(Runnable action, long delayMillis) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
return attachInfo.mHandler.postDelayed(action, delayMillis);
}
// Assume that post will succeed later
ViewRootImpl.getRunQueue().postDelayed(action, delayMillis);
return true;
}
I use this:
Thread closeActivity = new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(3000);
// Do some stuff
} catch (Exception e) {
e.getLocalizedMessage();
}
}
});
I use CountDownTime
new CountDownTimer(5000, 1000) {
#Override
public void onTick(long millisUntilFinished) {
// do something after 1s
}
#Override
public void onFinish() {
// do something end times 5s
}
}.start();
You probably don't want to do it that way. By putting an explicit sleep() in your button-clicked event handler, you would actually lock up the whole UI for a second. One alternative is to use some sort of single-shot Timer. Create a TimerTask to change the background color back to the default color, and schedule it on the Timer.
Another possibility is to use a Handler. There's a tutorial about somebody who switched from using a Timer to using a Handler.
Incidentally, you can't pause a process. A Java (or Android) process has at least 1 thread, and you can only sleep threads.
This is what I did at the end of the day - works fine now :
#Override
public void onClick(View v) {
my_button.setBackgroundResource(R.drawable.icon);
// SLEEP 2 SECONDS HERE ...
final Handler handler = new Handler();
Timer t = new Timer();
t.schedule(new TimerTask() {
public void run() {
handler.post(new Runnable() {
public void run() {
my_button.setBackgroundResource(R.drawable.defaultcard);
}
});
}
}, 2000);
}
In addition to Mr. Yankowsky's answers, you could also use postDelayed(). This is available on any View (e.g., your card) and takes a Runnable and a delay period. It executes the Runnable after that delay.
This is my example
Create a Java Utils
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
public class Utils {
public static void showDummyWaitingDialog(final Context context, final Intent startingIntent) {
// ...
final ProgressDialog progressDialog = ProgressDialog.show(context, "Please wait...", "Loading data ...", true);
new Thread() {
public void run() {
try{
// Do some work here
sleep(5000);
} catch (Exception e) {
}
// start next intent
new Thread() {
public void run() {
// Dismiss the Dialog
progressDialog.dismiss();
// start selected activity
if ( startingIntent != null) context.startActivity(startingIntent);
}
}.start();
}
}.start();
}
}
Or you could use:
android.os.SystemClock.sleep(checkEvery)
which has the advantage of not requiring a wrapping try ... catch.
If you use Kotlin and coroutines, you can simply do
GlobalScope.launch {
delay(3000) // In ms
//Code after sleep
}
And if you need to update UI
GlobalScope.launch {
delay(3000)
GlobalScope.launch(Dispatchers.Main) {
//Action on UI thread
}
}
I know this is an old thread, but in the Android documentation I found a solution that worked very well for me...
new CountDownTimer(30000, 1000) {
public void onTick(long millisUntilFinished) {
mTextField.setText("seconds remaining: " + millisUntilFinished / 1000);
}
public void onFinish() {
mTextField.setText("done!");
}
}.start();
https://developer.android.com/reference/android/os/CountDownTimer.html
Hope this helps someone...
class MyActivity{
private final Handler handler = new Handler();
private Runnable yourRunnable;
protected void onCreate(#Nullable Bundle savedInstanceState) {
// ....
this.yourRunnable = new Runnable() {
#Override
public void run() {
//code
}
};
this.handler.postDelayed(this.yourRunnable, 2000);
}
#Override
protected void onDestroy() {
// to avoid memory leaks
this.handler.removeCallbacks(this.yourRunnable);
}
}
And to be double sure you can be combined it with the "static class" method as described in the tronman answer
I'm sure this error is because I don't fully understand threads, but here it goes...
I have a runnable that is started when onCreate() is called within a method:
#Override
protected void onCreate(Bundle savedInstanceState) {
//Set all app specific starting points here
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_avatar);
...
soundMeterLoop();
}
public void soundMeterLoop() {
Log.d("SpeechKit", "Start Sound Meter");
soundMeterHandler = new Handler();
soundMeterRunnable = new Runnable() {
#Override
public void run() {
if(!soundMeter.SoundMeterRunning) {
Log.d("SpeechKit", "Start SoundMeter in the runnable");
startSoundMeter();
}
if (soundMeter.mMediaRecorder != null) {
amplitude = soundMeter.getAmplitude();
decibelLevelOutput.setText("" + amplitude);
if (amplitude > threshold) {
decibelLevelOutput.setTextColor(Color.RED);
Log.d("SpeechKit", "Interrupt and run startNuance()");
startNuance();
} else {
decibelLevelOutput.setTextColor(Color.BLACK);
Log.d("SpeechKit", "Running");
soundMeterHandler.postDelayed(this, 100);
}
}
}
};
soundMeterHandler.postDelayed(soundMeterRunnable, 100);
}
This runs just fine when it's created in the onCreate. As you can see, it kills itself (by not renewing the loop if the statement fails) and runs startNuance().
public void startNuance() {
soundMeterHandler.removeCallbacksAndMessages(soundMeterRunnable);
nuance.toggleReco();
}
I then kill the runnable and start a method in another class. This class runs fine, then when it's finished doing its thing, I call back to this main class with avatar.stopNuance();
This is in the Nuance.java class
#Override
public void onFinishedRecording(Transaction transaction) {
Log.d("SpeechKit", "onFinishedRecording");
//We have finished recording the users voice.
//We should update our state and stop polling their volume.
state = State.PROCESSING;
stopAudioLevelPoll();
avatar.stopNuance(); // <<<<<
}
It then returns back to my main activity (avatar) and runs this stopNuance() method:
public void stopNuance() {
Log.d("SpeechKit", "stopNuance(), start loop again");
soundMeterLoop();
}
Then it tries to run the same loop from before. Only this time, I'm getting a lot of errors that pertain to nullpointerexceptions. specifically starting with decibelLevelOutput.setText("" + amplitude);
I'm not sure why these things are null or how to fix them. Is this because it started a new thread that was not started in the creation of the runnable?
After talking on chat the actual issue was elsewhere in the codebase.
The problem was this:
public class Nuance {
private Activity activity;
private Session session;
public Avatar avatarActivity = new Avatar(); // DONT DO THIS
....
#Override
public void onFinishedRecording(Transaction transaction) {
Log.d("SpeechKit", "onFinishedRecording");
//We have finished recording the users voice.
//We should update our state and stop polling their volume.
state = State.PROCESSING;
stopAudioLevelPoll();
avatarActivity.stopNuance();
}
You should never, ever ever create your own instance of an Activity. They are creted and managed by the system. The system will call the lifecycle methods on the instance (onCreate etc) but if you create an instance these methods are not called - therefore a lot of strange behaviour happens.
The fix here is this:
public class Nuance {
private Avatar activity;
private Session session;
....
#Override
public void onFinishedRecording(Transaction transaction) {
Log.d("SpeechKit", "onFinishedRecording");
//We have finished recording the users voice.
//We should update our state and stop polling their volume.
state = State.PROCESSING;
stopAudioLevelPoll();
activity.stopNuance();
}
you don't want to create a new runnable everytime soundMeterLoop() is called.
Try this:
private final Handler soundMeterHandler = new Handler();
#Override
protected void onCreate(Bundle savedInstanceState) {
//Set all app specific starting points here
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_avatar);
...
soundMeterLoop();
}
public void soundMeterLoop() {
Log.d("SpeechKit", "Start Sound Meter");
soundMeterHandler.postDelayed(soundMeterRunnable, 100);
}
private final Runnable soundMeterRunnable = new Runnable() {
#Override
public void run() {
if(!soundMeter.SoundMeterRunning) {
Log.d("SpeechKit", "Start SoundMeter in the runnable");
startSoundMeter();
}
if (soundMeter.mMediaRecorder != null) {
amplitude = soundMeter.getAmplitude();
decibelLevelOutput.setText("" + amplitude);
if (amplitude > threshold) {
decibelLevelOutput.setTextColor(Color.RED);
Log.d("SpeechKit", "Interrupt and run startNuance()");
startNuance();
} else {
decibelLevelOutput.setTextColor(Color.BLACK);
Log.d("SpeechKit", "Running");
soundMeterHandler.postDelayed(this, 100);
}
}
}
};
I want to make stopwatch. And i create stopwatch class like this. And when i call onPause in another Activity its freeze application.
public class StopWatch implements Runnable {
private Object mPauseLock;
private boolean mPaused;
private boolean mFinished;
private ArrayList<TextView> textFields;
private Handler mHandler = new Handler();
public StopWatch( ArrayList<TextView> textFields) {
mPauseLock = new Object();
mPaused = false;
mFinished = false;
this.textFields =textFields;
}
public void run() {
textFields.get(1).setText("progressing...");
if (!mPaused) {
mHandler.postDelayed(this, 1000);
}
synchronized (mPauseLock) {
while (mPaused) {
try {
mPauseLock.wait();
} catch (InterruptedException e) {
}
}
}
}
public void onPause() {
synchronized (mPauseLock) {
mPaused = true;
}
}
public void onResume() {
synchronized (mPauseLock) {
mPaused = false;
mPauseLock.notifyAll();
}
}
}
and i create instance of class in another View like. Can somebody exmplain me where is problem?
stopky = new StopWatch(textFields);
stopky.run();
// do another stuff and register buttons with onClickListener and call
stopky.onPause(); // freeze application
stopky.onResume();
You can't Object.wait() in a run method called from a Handler, which is probably running on the main/UI Thread.
The whole Android app is coordinated via short methods which register with the main/UI Thread. You're probably registering your stopwatch there, too. It's not possible to perform a while loop there and at the same time process events from the user interface..
A quick solution would be to re-schedule your run method and check the status the next time it gets called. Basically like so:
public void run() {
textFields.get(1).setText("progressing...");
if (!mPaused) {
// do what has to be done when stopwatch is running
mHandler.postDelayed(this, 1000);
} else {
// just re-schedule with a shorter delay
mHandler.postDelayed(this, 10);
}
}
An even better way would be to go for a fully event-driven design and avoid calling the stopwatch at all while it is stopped. In this case, you would simply re-start it from the Button's event handler.
I have a question related to the following link: What's the difference between Thread start() and Runnable run()
In this question, I see a person creating runnable objects and then initializing them in two different ways. So, does this mean that you could pass these runnables around to other things at run time?
I want to pass code to a preexisting thread to be executed within that thread's loop. I was looking around and from what I can tell, you would want to create a dedicated runnable class like the following:
public class codetobesent implements Runnable
{
public void run()
{
..morecodehere.
}
...insertcodestuffhere
}
But how would I pass this to a thread that is already running? Say I'm trying to make a game and I have something special I want the renderer to do in its thread. How would I pass this runnable to that thread and have it run this data correctly?
My current implementation of my rendering thread is the following, I pulled it off of a tutorial site, and it has worked pretty well so far. But I want to know how to pass things to it so I can run more than what's just in the preset loop.
class RenderThread extends Thread
{
private SurfaceHolder _curholder;
private UserView curview;
private boolean runrender = false;
public RenderThread (SurfaceHolder holder, UserView thisview)
{ //Constructor function - This gets called when you create a new instance of this object.
curview = thisview;
_curholder = holder;
}
public SurfaceHolder getThreadHolder()
{
return _curholder;
}
public void setRunning(boolean onoff)
{
runrender = onoff;
}
#Override
public void run()
{
Canvas c;
while (runrender)
{
c = null; //first clear the object buffer.
try
{
c = _curholder.lockCanvas(null); //lock the canvas so we can write to it
synchronized (_curholder)
{//we sync the thread with the specified surfaceview via its surfaceholder.
curview.onDraw(c);
}
}
finally
{
// do this in a finally so that if an exception is thrown
// during the above, we don't leave the Surface in an
// inconsistent state
if (c != null)
{
_curholder.unlockCanvasAndPost(c);
}
}
}
}
}
A Handler Thread implementation.
private void testWorker(){
WorkerThread worker = new WorkerThread();
worker.start();
for (int i = 0; i < 10; i++) {
worker.doRunnable(new Runnable() {
public void run() {
Log.d("demo", "just demo");
try {
Thread.sleep(1000);//simulate long-duration operation.
} catch (InterruptedException e) {
e.printStackTrace();
}
};
});
}
}
private class WorkerThread extends HandlerThread implements Callback {
private Handler mHandler;
public WorkerThread() {
super("Worker");
}
public void doRunnable(Runnable runnable) {
if (mHandler == null) {
mHandler = new Handler(getLooper(), this);
}
Message msg = mHandler.obtainMessage(0, runnable);
mHandler.sendMessage(msg);
}
#Override
public boolean handleMessage(Message msg) {
Runnable runnable = (Runnable) msg.obj;
runnable.run();
return true;
}
}
I am writing a game in which after a specified amount of time a thread must be stopped.The user has failed to complete a particular level.I am using a thread.How do i stop this thread after a specified amount of time and display another view.How do i do this.The following code delays the launching of the thread by timelimit.
Thread t = ... t.join(timelimit);
if (t.isAlive)
t.interrupt();
How do i run the thread and close it after a period of time.
Your working thread
public class Worker extends Thread {
private boolean isRunning = true;
public void run() {
while (isRunning) {
/* do your stuff here*/
}
}
public void stopWorker() {
isRunning = false;
}
}
Your stopping thread
public class Stopper extends Thread {
private Worker worker;
public void Stopper(Worker w) {
worker = w;
}
public void run() {
// wait until your timeout expires
worker.stopWorker();
}
}
you should declare your thread with something like this
public class GameLoopThread extends Thread{
private boolean running = false;
public void setRunning(boolean run){
running = run;
}
#Override
public void run(){
while(running){
}
}
}
This is the safer way, In order to stop you should set the running variable to false. Otherwise If you stop the thead you will get an android exception .
I prefer interrupting the Thread from outside and checking interrupted state in short intervals:
try {
while (!Thread.currentThread.interrupted()) {
doSth();
}
} catch (InterruptedException e) {
// finished
}
you can use below code is run after given specified time.
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
// after this is rung
}
}, 5000);