i have an ImageView in which the picture switches every 5s, i am trying to add a pause and
resume button that can stop and restart the action. i am using a Handler, Runnable, and
postDelay() for image switch, and i put the code on onResume. i am thinking about using
wait and notify for the pause and resume, but that would mean creating an extra thread. so
far for the thread, i have this:
class RecipeDisplayThread extends Thread
{
boolean pleaseWait = false;
// This method is called when the thread runs
public void run() {
while (true) {
// Do work
// Check if should wait
synchronized (this) {
while (pleaseWait) {
try {
wait();
} catch (Exception e) {
}
}
}
// Do work
}
}
}
and in the main activity's onCreate():
Button pauseButton = (Button) findViewById(R.id.pause);
pauseButton.setOnClickListener(new View.OnClickListener()
{
public void onClick(View view)
{
while (true) {
synchronized (thread)
{
thread.pleaseWait = true;
}
}
}
});
Button resumeButton = (Button) findViewById(R.id.resume);
resumeButton.setOnClickListener(new View.OnClickListener()
{
public void onClick(View view)
{
while (true) {
// Resume the thread
synchronized (thread)
{
thread.pleaseWait = false;
thread.notify();
}
}
}
});
the pause button seems to work, but then after that i can't press any other button, such as
the resume button.
thanks.
i am using a Handler, Runnable, and
postDelay() for image switch
Why? Why not use postDelayed() and get rid of the Thread and Handler?
void doTheImageUpdate() {
if (areWeStillRunning) {
myImageView.setImageResource(R.drawable.whatever);
myImageView.postDelayed(updater, 5000);
}
}
Runnable updater=new Runnable() {
public void run() {
doTheImageUpdate();
}
};
When you want to start updating, set areWeStillRunning to true and call doTheImageUpdate(). When you want to stop updating, set areWeStillRunning to false. You'll need to work out the edge case of where the user presses pause and resume within 5 seconds, to prevent doubling things up, but I leave that as an exercise for the reader.
If you really want to use a background thread, you will want to learn more about how to use background threads. For example, while(true) {} without any form of exit will never work. There are some good books on the subject, such as this one.
sorry to answer my own question, but the comment section is too small.
i did this (per CommonsWare):
private Runnable mWaitRunnable = new Runnable() {
public void run()
{
doTheImageUpdate();
}
};
private void doTheImageUpdate()
{
try
{
if(bStillRunning)
{
sText = "Step one: unpack egg";
iDrawable = R.drawable.monster2;
t.setText(sText);
mImage = BitmapFactory.decodeResource(getResources(), iDrawable);
imageView.setImageBitmap(mImage);
tts1 = new TTS(getApplicationContext(), ttsInitListener, true);
mHandler.postDelayed(mWaitRunnable, 5000);
}
}
catch (Exception e)
{
Log.e("mWaitRunnable.run()", e.getMessage());
}
}
Button pauseButton = (Button) findViewById(R.id.pause);
pauseButton.setOnClickListener(new View.OnClickListener()
{
public void onClick(View view)
{
bStillRunning = false;
}
});
Button resumeButton = (Button) findViewById(R.id.resume);
resumeButton.setOnClickListener(new View.OnClickListener()
{
public void onClick(View view)
{
bStillRunning = true;
}
});
again pause works but resume doesn't. and i have already simplified my problem by making the text, the image, and delay time the same for all the steps. i was hoping to make these variable, in additional to the number of steps.
Related
I am trying to perform sort of a stop light function on a button press but instead there are two of every color. The desired functionality would be red, red, yellow, yellow, green, and green. I have tried to set a delay in between each color but it doesn't happen sequentially it just adds up the delays and they all show up at once.
Here is the snippet of the activity that I have tried to do this:
Button previewButton = (Button) findViewById(R.id.preview_visual_button);
final Button redButton1 = (Button) findViewById(R.id.red_button_1);
final Button redButton2 = (Button) findViewById(R.id.red_button_2);
final Button yellowButton1 = (Button) findViewById(R.id.yellow_button_1);
final Button yellowButton2 = (Button) findViewById(R.id.yellow_button_2);
final Button greenButton1 = (Button) findViewById(R.id.green_button_1);
final Button greenButton2 = (Button) findViewById(R.id.green_button_2);
redButton1.setVisibility(View.GONE);
redButton2.setVisibility(View.GONE);
yellowButton1.setVisibility(View.GONE);
yellowButton2.setVisibility(View.GONE);
greenButton1.setVisibility(View.GONE);
greenButton2.setVisibility(View.GONE);
if(previewButton != null) {
previewButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int time = 100;
delay(time);
}
});
}
}
public void delay(final int c){
runOnUiThread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(c);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
Button redButton1 = (Button) findViewById(R.id.red_button_1);
Button redButton2 = (Button) findViewById(R.id.red_button_2);
Button yellowButton1 = (Button) findViewById(R.id.yellow_button_1);
Button yellowButton2 = (Button) findViewById(R.id.yellow_button_2);
Button greenButton1 = (Button) findViewById(R.id.green_button_1);
Button greenButton2 = (Button) findViewById(R.id.green_button_2);
redButton1.setVisibility(View.VISIBLE);
redButton2.setVisibility(View.VISIBLE);
yellowButton1.setVisibility(View.VISIBLE);
yellowButton2.setVisibility(View.VISIBLE);
greenButton1.setVisibility(View.VISIBLE);
greenButton2.setVisibility(View.VISIBLE);
}
}, c);
}
EDIT:
previewButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int time = 1000;
redButton1.setVisibility(View.VISIBLE);
delay(time);
redButton2.setVisibility(View.VISIBLE);
delay(time);
yellowButton1.setVisibility(View.VISIBLE);
delay(time);
yellowButton2.setVisibility(View.VISIBLE);
delay(time);
greenButton1.setVisibility(View.VISIBLE);
delay(time);
greenButton2.setVisibility(View.VISIBLE);
}
});
}
public void delay(final int time) {
new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
Because that's basically what the postDelayed method does. It runs the code in the runnable after the specified time. So it delays for 100ms then runs just turns all the buttons on at once. Also I'm not sure what you are trying to do by calling Thread.sleep() on your UI thread. I would suggest writing a new method that just runs a Thread.sleep() inside a separate thread and call it between each pair of button toggle commands. Kind of like this
public void pause(int time) {
new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
Then basically call this in between each pair of button toggle statements. This should do the trick.
Update UI with Thread sleep
This will help answer the question if anyone visits in the future.
public class MainActivity extends Activity {
ImageView img;
MediaPlayer failure;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button bButton= (Button)findViewById(R.id.blueBtn);
img = (ImageView)findViewById(R.id.image);
img.setVisibility(View.VISIBLE);
failure= MediaPlayer.create(this,R.raw.failure_sound);
bButton.setOnClickListener(new View.OnClickListener(){
public void onClick(View v){
img.setVisibility(View.VISIBLE);
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
failure.start();
}
});
}
well thats my code.
I just want to make that when I press the button it'll show the image
then wait 1000 miliseconds, and then make a sound.
BUT(!) unfortunaltly when I press that button: the process waits 1000 ms, and then make the sound and shows the img.
help plz!!!
Replace your onClick handler:
public void onClick(View v){
img.setVisibility(View.VISIBLE);
v.postDelayed(new Runnable() {
public void run() { failure.start(); }
},1000);
}
With Thread.sleep(10000); you are causing the main thread to freeze and thus the UI cannot be updated for that amount of time.
If you want to wait for a certain amount of time to do something, you may use a Handler instead, so the UI can be updated in the meantime:
public void onClick(View v){
img.setVisibility(View.VISIBLE);
new Handler().postDelayed(new Runnable() {
public void run() {
failure.start();
}
}, 1000);
}
You're putting your UI thread to sleep, which causes your app to freeze and the image not showing up.
A better approach for this is to use a handler, which will execute code after a delay and will not freeze your UI.
A quick adaption of your clickListener would be:
bButton.setOnClickListener(new View.OnClickListener(){
public void onClick(View v){
img.setVisibility(View.VISIBLE);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
failure.start();
}
}, 1000);
});
}
So I have an activity which runs a simple snakes and ladders game, and I want to allow the player to click a button and move, which would subsequently be followed by the computer moving. My problem is, that once the player moves, the computer immediately makes its move.
Instead I want the activity to wait before the computer makes its move. I've looked around a lot and found that waiting involves using a thread, but I have failed to implement it without my app crashing
My attempt at declaring a thread:
final Runnable runnable = new Runnable() {
#Override
public void run()
{
while (true)
{
try
{
Thread.sleep(5000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
};
Thread thread= new Thread(runnable);
My onClick() method for the button:
Button rollButton = (Button) (findViewById(R.id.rollButton));
rollButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//executes only if current player is a human
if(GAME_BOARD.getCurrentPlayer().isHuman()) {
GAME_BOARD.rollDie(); // rolls the die
showDie(GAME_BOARD); // displays die on screen
GAME_BOARD.move(); // moves the player and sets next player as current player
playerTurn.setText(GAME_BOARD.getCurrentPlayer().getName() +"'s turn");// sets TextView to display who's player's turn it is
thread.start();
if(!GAME_BOARD.getCurrentPlayer().isHuman()) {
GAME_BOARD.rollDie();
showDie(GAME_BOARD);
GAME_BOARD.move();
playerTurn.setText(GAME_BOARD.getCurrentPlayer().getName() +"'s turn");
}
}
}
});
So again, my question is, how do I make it so that before the second if statement executes, the activity waits, say 4 seconds?
you can use an Handler.postDeleayed. You have to provide a Runnable to execut and the delay period in milliseconds. The Runnable will be executed on the UI Thread
You can use Handle to post your task defined in runnable after some delay
use this
Inside Activity define
Handler hand = new Handler();
and define your task in runnable like this
Runnable run = new Runnable() {
#Override
public void run() {
**your Task here.......**
}
};
In on click event
btnStartShow.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
hand.postDelayed(run,3000); // For delay three seconds
}
});
also remove all pending messages by calling following sentence at appropriate place
hand.removeCallbacksAndMessages(null);
Use a CountDownTimer:
CountDownTimer timer = new CountDownTimer(4000, 1000) {
#Override
public void onFinish() {
*function containing the second statement*
}
#Override
public void onTick(long millisLeft) {
// not ticking
}
};
and in the onClick method in the click listener use:
timer.start();
Try the following,
rollButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Runnable runnable = new Runnable() {
#Override
public void run() {
// whatever you would like to implement when or after clicking rollButton
}
};
rollButton.postDelayed(runnable, 5000); //Delay for 5 seconds to show the result
}
I have this code for changing the screen color.
But I don't know how to stop this thread:
lin = (LinearLayout)findViewById(R.id.mainlayout);
new Thread(new Runnable() {
public void run() {
while (finalStatus < 1) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
colorHandler.post(new Runnable() {
public void run() {
if(flag)
{
lin.setBackgroundColor(Color.BLUE);
flag = false;
}
else
{
lin.setBackgroundColor(Color.RED);
flag = true;
}
}
});
}
}
}).start();
I tried to put:
Button btn = (Button) findViewById(R.id.button1);
btn.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
Toast.makeText(getBaseContext(),"STOP",Toast.LENGTH_SHORT).show();
finalStatus=1;
lin.setBackgroundColor(Color.BLACK);
}
});
and the thread stopped, but the screen is red, or blue, I need black.
Moreover, how to start this thread after I have stopped it?
I'm not sure what's the scenario for getting a background blue or red but let's assume it's when you set the finalStatus to 1. In order to avoid changing the background and still exiting the thread you can set it to a different value in your button click listener, let's say to 111. Adding the following condition before colorHandler.post will solve the issue:
if (finalStatus == 111) {
return;
}
Just put that lin.setBackgroundColor(Color.BLACK); code after the While loop in the outer thread run() method. and dont forget to use the handler for the same since other than UI thread wont update the UI.
i creating for stopwatch with start,stop i use following code it started but not stop. please help me.
my code:
public class StopWatch2 extends Activity implements Runnable{
// text view influenced by the Thread
private TextView threadModifiedText;
int time=0;
Button b1,b2,b3;
/** Called when the activity is first created. */
Thread currentThread = new Thread(this);
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.stopwatch);
b1=(Button)findViewById(R.id.button1);
b2=(Button)findViewById(R.id.button2);
b3=(Button)findViewById(R.id.button3);
threadModifiedText = (TextView) findViewById(R.id.textView1);
b1.setOnClickListener(new View.OnClickListener()
{
public void onClick(View view)
{
currentThread.start();
}
});
b2.setOnClickListener(new View.OnClickListener()
{
public void onClick(View view)
{
currentThread.stop();
}
});
}
//Method you must override to control what the Thread is doing
#Override
public void run(){
try {
while(true){
currentThread.sleep(1000, 0);
threadHandler.sendEmptyMessage(0);
}
// signaling things to the outside world goes like this
} catch (InterruptedException e) {
}
}
private Handler threadHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
time++;
threadModifiedText.setText(""+time);
}
};
}
I think You should use a class level variable boolean shouldRun = true ;
in your run() method while should be used like this way
while(shouldRun)
{
//implementation
}
and in your b2.onClickListener() change shouldRun = false;
Edit:
For suspend and resume you can change the value of shouldRun to shouldRun = true; in the listener for resume button. Remember that when you stop the updates you should reset the time also. and in suspend the time should be remain same.
I implemented stopwatch for rotational puzzles solving time measurements and I have approached it somewhat differently.
For time measurements I use Handler object that triggers after DISPLAY_UPDATE_TIMEOUT. It is time after which you update display about time elapsed.
To start counting I use:
mLastStartTimestamp = System.currentTimeMillis();
mRepetitiveTimeoutHandler.postDelayed(processWatchTimer, DISPLAY_UPDATE_TIMEOUT);
and to stop it
mRepetitiveTimeoutHandler.removeCallbacks(processWatchTimer);
mStartStopElapsed = System.currentTimeMillis() - mLastStartTimestamp ;
updateTimeDisplay();
On each trigger of the handler I do the following:
private Runnable processWatchTimer = new Runnable()
{
public void run()
{
mRepetitiveTimeoutHandler.postDelayed(processWatchTimer, DISPLAY_UPDATE_TIMEOUT);
updateTimeDisplay();
}
};