How to stop postDelayed after x number of times - java

I am creating an animation that randomly selects a string that's pulled from an XML string array. It does this in rapid succession to make it look kind of like a slot machine. I got the animation going, but I do not know how to stop it after x times. Here's what I have thus far:
public class MainActivity extends AppCompatActivity {
TextView locationsTextView;
Button generateBtn;
String[] mArray;
int counter; //<-- This is how I would like to keep track of when handler should stop
Handler h = new Handler();
int delay = 50;
Runnable runnable;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
locationsTextView = findViewById(R.id.locationsTextView);
generateBtn = findViewById(R.id.generateBtn);
mArray = getResources().getStringArray(R.array.locations_array);
locationsTextView.setText("");
generateBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
h.postDelayed(new Runnable() {
public void run() {
updateTextView();
runnable = this;
h.postDelayed(runnable, delay);
}
}, delay);
}
});
}
private void updateTextView() {
Random random = new Random();
int maxIndex = mArray.length;
int generatedIndex = random.nextInt(maxIndex);
locationsTextView.setText(mArray[generatedIndex]);
}
}
I am thinking that something like this would work:
//pseudo code
//Button is clicked
//initialize counter to 0
counter = 0;
//updateTextView method is called repeatedly
counter ++;
if(counter == 50) {
h.removeCallbacksandMessages(null);
}
I just don't know where I would place that in the code.

If I would've taken a few more minutes before posting, I think I figured it out. See code below:
generateBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
counter = 0; //<-- every click, set back to 0
h.postDelayed(new Runnable() {
public void run() {
counter++; //<-- increment with every method call
updateTextView();
runnable = this;
h.postDelayed(runnable, delay);
if(counter == 50) { //<-- stop after 50
h.removeCallbacksAndMessages(null);
}
}
}, delay);
}
});
}

Related

Why value of only last iteration(999) is printed in the text field ? I want all numbers to be printed before getting replaced by next number

I am new to android studio and want to overcome from this problem.
It gonna help me a lot while creating some future apps like , stopwatch, timer etc etc.
Thanks in advance !!
public class MainActivity extends AppCompatActivity {
private EditText k;
private Button start;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
k=findViewById(R.id.kf);
start=findViewById(R.id.startf);
start.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
for(int i=1;i<1000;i++)
{
k.setText(String.valueOf(i) );
}
}
});
}
}
As #f1sh already mentioned in the comments your for loop is executing at such a speed that all you see is the final value. For such cases in android one of the best solutions is to make use of Handler for posting delayed functions without blocking the UI.
So for showing 1 to 999 you can try something like this:
public class MainActivity extends AppCompatActivity {
private EditText k;
private Button start;
int count;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
k=findViewById(R.id.kf);
start=findViewById(R.id.startf);
final Handler handler = new Handler();
final Runnable runnable = new Runnable() {
public void run() {
if (count < 1000) {
k.setText(String.valueOf(count));
count++;
handler.postDelayed(this, 1000);
} else {
handler.removeCallbacks(this);
}
}
};
start.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
count = 1;
handler.postDelayed(runnable, 0);
}
});
}
}
this will keep changing the text in TextView with a 1 second delay, you can change the delay as needed by setting the milliseconds in runnable.
You can even use a countdown timer for this purpose but its more like a workaround and requires you to calculate the correct time etc.
For example displaying 1 to 10 would be something like this:
...
count = 1;
new CountDownTimer(11000, 1000) {
public void onTick(long millisUntilFinished) {
tv.setText(String.valueOf(count));
count++;
}
public void onFinish() {
}
}.start();
here you are displaying the value every 1 second for 11 seconds

Change color of a button every second

I want to bulid a reaction game where you have to click on a colour changing button when it's the right color (red). How can i display a color and change it after a second to another random color till the right colour appears.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_farberkennung);
b_zurück = (Button) findViewById(R.id.b_zurück);
b_start3 = (Button) findViewById(R.id.b_start3);
b_randomColor = (Button) findViewById(R.id.b_randomcolor);
final int background;
final Random rand = new Random();
final List<Integer> list = new ArrayList<>();
list.add(getResources().getColor(R.color.red));
list.add(getResources().getColor(R.color.green));
list.add(getResources().getColor(R.color.yellow));
//list.add(getResources().getColor(R.color.blue));
//list.add(getResources().getColor(R.color.orange));
//list.add(getResources().getColor(R.color.olive));
//list.add(getResources().getColor(R.color.purple));
background = list.get(rand.nextInt(list.size()));
b_start3.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
b_start3.setEnabled(false);
b_randomColor.setBackgroundColor(background);
//loop random colours till red appears
while (background != getResources().getColor(R.color.red)) {
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
b_randomColor.setBackgroundColor(background);
}
}, 1000);
}
startTime = System.currentTimeMillis();
}
});
b_randomColor.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (background == (getResources().getColor(R.color.red))) {
endTime = System.currentTimeMillis();
currentTime = endTime - startTime;
b_randomColor.setText(currentTime + " MS");
b_randomColor.setEnabled(false);
b_start3.setEnabled(true);
}
}
});```
you can do it by this way :
create a new java class file called Timer
public class Timer {
private thread t ;
public boolean runTimer ;
public long delay ;
public int msg = 0;
private Handler handler ;
public Timer(Handler handler , long delay , int msg){
this.handler = handler ;
runTimer = true ;
this.delay = delay ;
this.msg = msg ;
t = new thread();
t.start();
}
public class thread extends Thread {
#Override
public void run(){
while (runTimer){
try{
thread.sleep(delay);
}catch (Exception e){}
Message message = handler.obtainMessage(msg);
handler.sendMessage(message);
}
}
}
public void playTimer (boolean play){
runTimer = play ;
}
}
then add this message handler inside your activity and inside that handler you can test your background color if it is red
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
.........
}
// here the code you add to your activity
private final Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
if (background != getResources().getColor(R.color.red)){
b_randomColor.setBackgroundColor(background);
}else {
// you could stop your timer thread like that ...
// timer.playTimer(false);
}
}
};
and finally start your timer inside your like that :
final Timer timer;
timer = new Timer(handler , 1000 , "time");

Button supposed to click 5 times through an string array, stop 5 secs and then continue(clicking 5 times) CONSISTENTLY, ERROR

My problem is I cant get my button to consistently click 5 times through a string array which is displayed in a TextView ,
whenever the maxclicks(5) and currentnumber get to 5 it stops working , Ive been trying to create if conditions to work around it, well somehow I have to manipulate my currentnumber to NOT be 5 because IF maxclicks == currentnumber my button is enabled.
In the Code below it stops just afte the first time of clicking 5 times.
so here is the Code :
public class MainActivity extends AppCompatActivity {
int currentnumber = 0;
int mod = 5;
TextView display = findViewById(R.id.tx);
Handler handler = new Handler();
int delay = 5000;
int maxclicks = list.length;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Resources res = getResources();
final String[] list = res.getStringArray(R.array.xyz);
final Button next_button = findViewById(R.id.next_btn);
{
((TextView) findViewById(R.id.tx)).setText(list[currentnumber]);
next_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(currentnumber == maxclicks){
currentnumber = 0;
}
if (currentnumber % mod == 0) {
next_button.setEnabled(false);
handler.postDelayed(new Runnable() {
#Override
public void run() {
//the button will unlock after the delay specified
next_button.setEnabled(true);
currentnumber++;
}
}, delay);
}
else {
display.setText(list[currentnumber]);
currentnumber++;
}
}
});
}
}
}
welcome to SO :) I did my best to understand on your explanation,so this is my solution for your problem and don't forget you can make your vars global to avoid final and one element array thing:
public class MainActivity extends AppCompatActivity {
private int currentnumber,mod,delay,Curclicks;
private TextView display;
private Handler handler;
private Button next_button;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_setting);
//Binding
display = findViewById(R.id.tx);
next_button = findViewById(R.id.next_button);
//getResources
Resources res = getResources();
//getting the data ready
String[] list = {"1","2","3","4","5","6","7"};
//assign vars
handler = new Handler();
currentnumber = 0;
Curclicks=0;
mod = 5;
delay = 5000;
//initial view
next_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(currentnumber == list.length){
currentnumber = 0;
}
if (Curclicks == mod-1) {
next_button.setEnabled(false);
display.setText(list[currentnumber]);
currentnumber++;
handler.postDelayed(new Runnable() {
#Override
public void run() {
//the button will unlock after the delay specified
next_button.setEnabled(true);
Curclicks = 0;
}
}, delay);
}
else {
display.setText(list[currentnumber]);
currentnumber++;
}
Curclicks++;
}
});
}
}

Checking integer against array index not working

I'm making an android app where you tap a button to stop a looping counter when it is showing a particular number. I have an array (aNums) holding some int values and want the counter to stop when it is clicked when showing the first number in the array (in this case "2"). For some reason however it decides to stop on "1" when clicked. I'm not sure if my code is just wrong or if there's a timing issue and it's stopping right when it's about to change to the number "2". Here is my code so far:
public class MainActivity extends Activity {
public int a = 0;
private Handler handler = new Handler();
TextView textView2;
Button Stop;
public Runnable myRunnable = new Runnable() {
#Override
public void run() {
updateText();
a = ++a % 10;
if (a < 10) {
handler.postDelayed(this, 1000);
}
}
};
public int aNums[] = { 2, 4, 6, 8, 10, 12 };
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView2 = (TextView) findViewById(R.id.textView2);
loop();
Stop = (Button)findViewById(R.id.Stop);
Stop.setOnClickListener(handler2);
}
View.OnClickListener handler2 = new View.OnClickListener() {
#Override
public void onClick(View v) {
if (a == aNums[0]) {
Stop();
}
}
}
public void loop() {
handler.post(myRunnable);
}
public void updateText() {
textView2.setText("" + a);
}
public void Stop() {
super.onStop();
handler.removeCallbacks(myRunnable);
}
}
Does anyone know what the problem is?
Thanks
You forgot two closing brackets here:
View.OnClickListener handler2 = new View.OnClickListener() {
#Override
public void onClick(View v) {
for (int i = 0; i <= aNums.length; i++) {
if (a == aNums[0]) {
Stop();
} //I added this
}
}
}//and this
but I think there is no need for a for loop here: you want to stop the thread when you click at the moment a equals the number in your array at index 0, right?
View.OnClickListener handler2 = new View.OnClickListener() {
#Override
public void onClick(View v) {
if (a == aNums[0]) {
Stop();
}
}
}
Also, this check is not necessary because a will never be 10 or more:
if (a < 10) {
handler.postDelayed(this, 1000);
}
The last thing: when you quit the thread, the text is not updated. Try adding the updateText() after the click:
View.OnClickListener handler2 = new View.OnClickListener() {
#Override
public void onClick(View v) {
if (a == aNums[0]) {
Stop();
updateText();
}
}
}

Play sound every 6-10 seconds

How do you repeat a sound every 6-10 seconds, meaning a random interval between 6 and 10? So the sound plays 6, then 7, 6, 10, etc? So far I have this, which works how I want and plays the sound “once” and changes the button on the screen. However to play the sound again i must click the button to “stop” then click again to “go”. I want to Hit then button and have the sound repeat every 6-10 seconds until you hit the stop button...
public class MainActivity extends ActionBarActivity {
MediaPlayer myMediaPlayer = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final MediaPlayer myMediaPlayer = MediaPlayer.create(this, R.raw.whistle);
Timer soundTimer = new Timer();
Random r = new Random();
//Button related to play btn
final Button startStopButton = (Button) findViewById(R.id.startstopbutton);
startStopButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (startStopButton.getText().equals("Start")) {
//start the sound
//change button color and text
startStopButton.setText("Stop");
startStopButton.setBackgroundColor(Color.RED);
myMediaPlayer.start();
} else {
//stop whistle
//change button color and text
startStopButton.setText("Start");
startStopButton.setBackgroundColor(Color.GREEN);
}
}
});
}
You can get a random number between 6 and 10 like this:
int max = 10;
int min = 6;
int randomNum = new Random().nextInt((max - min) + 1) + min;
int seconds = randomNum * 1000;
Here is an example to play a sound every 6 to 10 seconds:
private final Random mRandom = new Random();
private final Handler mHandler = new Handler();
private MediaPlayer mPlayer;
private boolean mKeepPlaying = true;
private void playMySound() {
if (mPlayer == null) {
mPlayer = MediaPlayer.create(this, R.raw.whistle);
}
int delayMillis = 1000 * mRandom.nextInt(5) + 6; // random number between 6 and 10
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
if (isFinishing()) {
// Check if the Activity is finishing.
return;
}
mPlayer.start();
if (mKeepPlaying) {
// play the sound again in 6 to 10 seconds
playMySound();
}
}
}, delayMillis);
}
Just call playMySound(); in onCreate(Bundle) and toggle mKeepPlaying when you want to stop.
You can use MediaPlayer.OnCompletionListener to accomplish this, whenever the playback completes get a random number between 6 and 10 and post a runnable to start playback again after the calculated random time.
Here is an example of doing this.
public class MainActivity extends Activity {
Button button1;
MediaPlayer mediaPlayer = null;
private final Random mRandom = new Random();
int delayMillis;
Handler handler;
Runnable runnable;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button1 = (Button) findViewById(R.id.button1);
handler = new Handler();
runnable = new Runnable() {
#Override
public void run() {
mediaPlayer.start();
}
};
button1.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
toggleMediaPlayer();
}
});
}
private void toggleMediaPlayer(){
if(mediaPlayer != null){
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer=null;
handler.removeCallbacks(runnable);
}else{
mediaPlayer = MediaPlayer.create(this, R.raw.hangouts_incoming_call);
mediaPlayer.setOnPreparedListener(new OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mp.start();
}
});
mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
delayMillis = 1000 * mRandom.nextInt(5) + 6;
handler.postDelayed(runnable,delayMillis);
}
});
}
}}
Hope This helps .

Categories

Resources