Android Studio give a FOR loop a delay - java

Im trying to build easy app that the user need to remmber on which buttons the computer pressed ..
Each button that clicked make a sound .. so in order to make each sound ,sound correctly I tried to give a little bit of delay between each click that the computer pressed...
So I make int[] that include the sequence of the way the computer click the buttons ( for 1 click on button1 , for 2 click on button 2 .... )
and now im trying to acually pressed the button haha
so I made this :
private void ClickButtons(int[] sequence) {
Button btcomp1 = (Button) findViewById(R.id.btComp1);
Button btcomp2 = (Button) findViewById(R.id.btComp2);
Button btcomp3 = (Button) findViewById(R.id.btComp3);
Button btcomp4 = (Button) findViewById(R.id.btComp4);
TextView check=(TextView)findViewById(R.id.textViewKq);
Handler handler = new Handler();
for (int i = 0; i < sequence.length; i++)
{
switch (sequence[i]) {
case 1:
btcomp1.performClick();
check.setText("4..");
timedelay();
break;
case 2:
btcomp2.performClick();
check.setText("3..");
timedelay();
break;
case 3:
btcomp3.performClick();
check.setText("2..");
timedelay();
break;
case 4:
btcomp4.performClick();
check.setText("1..");
timedelay();
break;
}
}
}
it didnt work well , I even thought that their is may be problem with the button so I set it for changing some Textview but its seems that its only enter to one case ... and the only delay was when I mover from the FirstActivity to the GameActivity
I really have nothing in the FirstActivity just field for UserName ...
Well I hopes you helped me guys and soory for grammer ><
This is the delay .. I tried to do something but all that do is to delay me a few seconds after I gor from actity 1 to another but do nothing in the main ..
private void timedelay() {
try{
Thread.sleep(2500);
}
catch (Exception e){
}
}

For this kind of thing you should definitely use the android.os.Handler to make a timer. And in the callback method, click the buttons. The method you are using now will probably block the main thread. This is really bad.
Luckily, I have already written a Timer class does this! Here is the whole class:
import android.os.Handler;
public class Timer {
private Handler handler;
private boolean paused;
private int interval;
private Runnable task = new Runnable () {
#Override
public void run() {
if (!paused) {
runnable.run ();
Timer.this.handler.postDelayed (this, interval);
}
}
};
private Runnable runnable;
public int getInterval() {
return interval;
}
public void setInterval(int interval) {
this.interval = interval;
}
public void startTimer () {
paused = false;
handler.postDelayed (task, interval);
}
public void stopTimer () {
paused = true;
}
public Timer (Runnable runnable, int interval, boolean started) {
handler = new Handler ();
this.runnable = runnable;
this.interval = interval;
if (started)
startTimer ();
}
}
Try to understand it. After you do that, you can use this timer like this:
final Timer t = new Timer(new Runnable() {
private int i = 1;
Button btcomp1 = (Button) MainActivity.this.findViewById(R.id.btComp1);
Button btcomp2 = (Button) MainActivity.this.findViewById(R.id.btComp2);
Button btcomp3 = (Button) MainActivity.this.findViewById(R.id.btComp3);
Button btcomp4 = (Button) MainActivity.this.findViewById(R.id.btComp4);
TextView check=(TextView)MainActivity.this.findViewById(R.id.textViewKq);
public void run() {
switch (i) {
case 1:
btcomp1.performClick();
check.setText("4..");
break;
case 2:
btcomp2.performClick();
check.setText("3..");
break;
case 3:
btcomp3.performClick();
check.setText("2..");
break;
case 4:
btcomp4.performClick();
check.setText("1..");
t.stopTimer();
break;
}
}
}, 1000, true);
Once this timer is created, it basically presses a button once a second. And set the text of check. When it presses it the fourth time, the timer stops.
Easy! (if you have the timer class)

Related

Change text in button

import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn_apple = (Button) findViewById(R.id.button_apple);
Button btn_cherry = (Button) findViewById(R.id.button_cherry);
Button btn_orange = (Button) findViewById(R.id.button_orange);
Button btn_waterLemon = (Button) findViewById(R.id.button_waterlemon);
btn_apple.setOnClickListener(new View.OnClickListener() {
boolean action = false;
#Override
public void onClick(View v) {
switch (v.getId()){
case R.id.button_apple:
if (!action) {
action = true;
btn_apple.setText("1");
}
else {
int i = Integer.parseInt(btn_apple.getText().toString());
btn_apple.setText(String.valueOf(i + 1));
}
break;
case R.id.button_cherry:
action = false;
if (!action) {
action = true;
btn_cherry.setText("1");
}
else {
int i = Integer.parseInt(btn_cherry.getText().toString());
btn_cherry.setText(String.valueOf(i + 1));
}
break;
}
}
});
}
}
I need to make it so that if a user clicks on button_apple and doesn't click on it for 3 seconds, its text becomes so superfluous. And if anyone knows why my text changes in button_apple, but not in button_cherry. Tell me, please.
You're setting the listener on your apple button. The cherry button doesn't have a listener on it.
Reconsider what you're trying to achieve and simplify it.
If the user clicks the apple button you need to do something.
If the user clicks the cherry button you need to do something (maybe something else).
If the user clicks the watermellon button, ... and so on.
// define your listeners
View.OnClickListener appleListener = new View.OnClickcListener() {
#Override
public void onClick(View v) {
// do whatever you need to do when the apple button is clicked
}
};
// same thing for cherry listener, make a listener to handle the click action
View.OnClickListener cherryListener = ...
// register the listeners
btnApple.setOnClickListener(appleListener);
btnCherry.setOnClickListener(cherryListener);
...
EDIT
To make something happen after a set amount of time you have to consider:
the inputs: which objects / variables influence the action
the output: what's supposed to happpen if all inputs are valid
the duration
With android you could use a handler. See the postDelayed method.
long delayMillis = 3000L; // duration after which to run your task
Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
#Override
public void run() {
//Do something after the delay in milliseconds
}
}, delayMillis);
All of this stuff has to be inside the click listener with the logic you need to implement.
"If a user clicks on button apple and doesn't click on it for three seconds"
You could do something like
View.OnClickListener appleListener = new View.OnClickcListener() {
AtomicInteger clicks = new AtomicInteger(0);
#Override
public void onClick(View v) {
int numClicks = clicks.incrementAndGet();
if (numClicks == 1) {
long delayMillis = 3000L; // duration after which to run your task
Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
#Override
public void run() {
if (clicks.get() == 1) {
// they only clicked once, do whatever you need to do to make the text superfluous
}
// put the number of clicks back to 0
clicks.set(0);
}
}, delayMillis);
}
} else {
// TODO
// it's been clicked more than once
// show a toast if you need to or do something else
}
}
I didn't test this so you'll probably have to modify it a bit but that's the general idea.

Android Studio Java: how do I force a redraw / display of the textbox during the loop?

I have the following code, which I was hoping would count up to 3 million on the screen.
It compiles and runs, displaying 3,000,000 at the end on the emulator. My question is how do I force a redraw / display of the textbox during the loop please?
/** Called when the activity has become visible. */
#Override
protected void onResume() {
super.onResume();
Log.d(msg, "The onResume() event");
TextView textbox1=(TextView)findViewById(R.id.TextView1);
for(double l=0; l<=3000000; l++){
textbox1.setText("" + l);
}
}
The view is only disabled after onResume has finished running.
You may want to set the text in the textview, update some state in the activity (like an int field), and register some code to run after a while and increment. Look at using Handler, AsyncTask, or other options to defer code.
Here's a quick-and-dirty example with Handler.
final long DELAY_MILLIS = 50;
final Handler handler = new Handler();
int num = 0;
final Runnable runnable = new Runnable() {
public void run() {
if (num >= 3000000) return;
textbox1.setText("" + num);
num++;
// re-register ourself to run in DELAY_MILLIS;
handler.postDelayed(runnable, DELAY_MILLIS);
}
};
TextView textbox1;
protected void onResume() {
// more efficient to look this up once
this.textbox1 = (TextView)findViewById(R.id.TextView1);
runnable.run(); // will register itself to re-run
}
According to this answer the best way to show an incremental value in a TextView is to use ValueAnimator
public void animateTextView(int initialValue, int finalValue, final TextView textview) {
ValueAnimator valueAnimator = ValueAnimator.ofInt(initialValue, finalValue);
valueAnimator.setDuration(1500);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
textview.setText(valueAnimator.getAnimatedValue().toString());
}
});
valueAnimator.start();
}

Handling multiple Runnables() in Android

I'm trying to animate 4 images in succession, switching the animation when I get a new GCM message that sends a Broadcast Intent. I'll show the code for the first 2, and what is going wrong. Basically between the two commands(case 0 vs case 1), I need to be able to stop the first runnable and then start the 2nd. I try to do that by setting
isRunning = false;
but that doesn't work. I'm thinking if I kept hacking away I may get this right, but I am wondering what the correct way to do it is.
public void startAnimatedBackground(Integer num) {
isRunning = false;
ImageSwitcher imageSwitcher = null;
aniIn = AnimationUtils.loadAnimation(this,
android.R.anim.fade_in);
aniOut = AnimationUtils.loadAnimation(this,
android.R.anim.fade_out);
aniIn.setDuration(500);
aniOut.setDuration(500);
switch (num) {
case 0:
imageSwitcher = (ImageSwitcher) findViewById(R.id.switcher_accept);
break;
case 1:
imageSwitcher = (ImageSwitcher) findViewById(R.id.switcher_on_way);
break;
default:
break;
}
imageSwitcher.setInAnimation(aniIn);
imageSwitcher.setOutAnimation(aniOut);
imageSwitcher.setFactory(this);
imageSwitcher.setImageResource(images[0]);
isRunning = true;
final Handler handler = new Handler();
final ImageSwitcher finalImageSwitcher = imageSwitcher;
Runnable runnable = new Runnable() {
#Override
public void run() {
if (isRunning) {
System.out.println("Running.."+finalImageSwitcher+index);
index++;
index = index % images.length;
finalImageSwitcher.setImageResource(images[index]);
handler.postDelayed(this, interval);
}
}
};
handler.postDelayed(runnable, interval);
}
This is what happens at first, and it is correct. I get a blinking image.
...app:id/switcher_accept}1
...app:id/switcher_accept}0
...app:id/switcher_accept}1
...app:id/switcher_accept}0
...app:id/switcher_accept}1
After case 2 runs, this is what the running process looks like. As you can see, both are running, and none of the expected behavior is happening. What I want is the 2nd(switcher_on_way) to run just like the first was before. I was hoping my isRunning=false; code would let this happen, but it obviously isn't.
...app:id/switcher_on_way}0
...app:id/switcher_accept}1
...app:id/switcher_on_way}0
...app:id/switcher_accept}1
...app:id/switcher_on_way}0
...app:id/switcher_accept}1
Your problem lies in this block:
Runnable runnable = new Runnable() {
#Override
public void run() {
if (isRunning) {
System.out.println("Running.."+finalImageSwitcher+index);
...
handler.postDelayed(this, interval);
}
}
};
handler.postDelayed(runnable, interval);
You tried to create a loop and control it via isRunning variable. However, the problem is the condition is checked in the middle of the interval when isRunning is true.
1: Start _isRunning=false______Check(isRunning)________Check(isRunning)
2: ___Start _isRunning=false___isRunning=true_______isRunning=true
and you need other approach, for example: create global handler instead of local and then cancel the postDelayed when you start a new animation.
Refer to: cancelling a handler.postdelayed process
or you can use wait, synchronized, and notify.

How to add time to a running countdown timer?

Before I start I have looked at lots of threads including:
How to add time to countdown timer?
Android game countdown timer
But I just cant get my timer to work in the way I require. I want the timer to be counting down from say 30 and when and image is pressed (named imageview1 in this case) the timer adds 3 seconds to the timer to give it more time. I know you cannot essentially add the time while its running and you need to cancel and then start a new timer, The code I have so far is :
public void onClick(View v) {
// TODO Auto-generated method stub
//GlobalClass global = new GlobalClass();
Random rand = new Random();
CountDownTimer thetimer = new myTimer(millisInFuture, 1000);
switch(v.getId()) {
case R.id.buttonstart:
btnstart.setVisibility(View.INVISIBLE);
thetimer.start();
break;
case R.id.imageView1:
if (thetimer != null){
thetimer.cancel();
thetimer = new myTimer(countdownPeriod + 3000, 1000).start();
}
break;
with lots of other case references then :
public class myTimer extends CountDownTimer {
public myTimer(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}
#Override
public void onTick(long millisUntilFinished) {
timedisplay.setText("Time Left: " + millisUntilFinished / 1000);
countdownPeriod=millisUntilFinished;
}
#Override
public void onFinish() {
timedisplay.setText("Timer Finished");
started = false;
btnstart.setVisibility(View.VISIBLE);
}
}
I think the problem is its not cancelling the original timer so the label that shows the timer does some crazy things, like jumping around on different numbers both up and down as there would appear more than 1 class of thetimer. That is even though I have included the line thetimer.cancel(); The timer works fine if I just let it run to 0.
Any help would be great
You should not create your timer as a local in onClick. Instead create it as a global and start it somewhere else (in onCreate perhaps).
What happens with your current code is that whenever onClick is called a new timer is created and you then cancel the new timer - which has no effect on any previously created timer(s).
Try something like this:
public class MyActivity extends Activity {
CountDownTimer thetimer;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
thetimer = new myTimer(millisInFuture, 1000);
}
public void onClick(View v) {
Random rand = new Random();
switch(v.getId()) {
case R.id.buttonstart:
btnstart.setVisibility(View.INVISIBLE);
thetimer.start();
break;
case R.id.imageView1:
if (thetimer != null) {
thetimer.cancel();
thetimer = new myTimer(countdownPeriod + 3000, 1000).start();
}
break;
}
}
}
You will still have to keep track of the global time somewhere - i.e. the countDonwPeriod used to re-create the timer instance when an image is touched - it should probably be extracted from the timer before canceling it.

Android Java - Message at a random range of time, every second check

For a side project of mine, I'm devoloping an android app with java. I don't know java a lot but i'm trying ^^.
The project is to have an Alarm at a random time in a certain range. The problem is that my chronometer and button freeze, but everything still works! Does anyone has maybe another solution for the thread.sleep ??
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void StartChrono(View view) {
final Chronometer chrono = (Chronometer)findViewById(R.id.chronometer1);
chrono.setBase(SystemClock.elapsedRealtime());
chrono.start();
//Tick();
}
public int RandomTime(int min, int max)
{
int random = max - min;
Random rand= new Random();
random = rand.nextInt(random)+min;
return random;
}
public boolean CheckUp(int randomtime,int chronotime)
{
boolean check = false;
if(randomtime== chronotime)
{
check = true;
}
return check;
}
public void Tick()
{
boolean check = false;
int randomtime = RandomTime(20,150);
int time=1;
do
{
check = CheckUp(randomtime,time);
time = time +1;
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
AlertDialog alertDialog;
alertDialog = new AlertDialog.Builder(this).create();
alertDialog.setTitle("Error - 000");
alertDialog.setMessage("Could not check!");
alertDialog.show();
}
}while(check == false);
if(check == true)
{
AlertDialog alertDialog;
alertDialog = new AlertDialog.Builder(this).create();
alertDialog.setTitle("Yuy");
alertDialog.setMessage("Switch!");
alertDialog.show();
}
}
}
I wouldn't use Thread.sleep(), I would use a Timer.
You can set a time and the Timer automatically calls the associated task.
In Android it would work something like this:
http://android.okhelp.cz/timer-simple-timertask-java-android-example/
I used it once myself, but that is some time ago.
Btw.:
You don't have to write a method to check for a boolean value.
This also works:
boolean check = 5>3;
System.out.println("check: " + check);//"check true"
I'd definately use a Handler for this task: http://developer.android.com/reference/android/os/Handler.html
A basic example would be this:
long timeDelay = 1000; // Set this to your random number.
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
// Do whatever you need to do after a specified interval.
}
}, timeDelay);
Instantiate the Handler inside your onCreate and keep the reference around so you can call it inside your method.
Just to clarify, why you can't use Thread.sleep() for "sleeping" a specific amount of time, is this: when you call Thread.sleep() you call it on the UI thread, so every component running on the UI thread (buttons, textfields and so on) will "sleep" for the given amount of time and hence you basically halt the whole application.
Also see the documentation for Thread.sleep:
Causes the thread which sent this message to sleep for the given
interval of time (given in milliseconds).

Categories

Resources