I'm creating a TicTacToe game and currently, after someone wins, I have a postDelayed function that triggers after 5 milliseconds. During these 500 milliseconds, I can draw the winning character as well as display the winning animation. I was wondering if it was possible to make the user wait a mandatory 500 milliseconds and then tap to continue after the delay. Is this possible?
private void player1Wins() {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
buttons[i][j].setEnabled(false);
}
}
player1Points++;
textViewPlayer1.setText(Integer.toString(player1Points));
Toast.makeText(this, "Player 1 has won", Toast.LENGTH_SHORT).show();
final Handler handler = new Handler();
final Runnable r = new Runnable() {
public void run() {
resetBoard();
}
};
handler.postDelayed(r, 500);
winAnimation(winCondition);
}
'Yeah you can do it. You can hide the button from xml in its properties like.'
android:visibility="gone";
'in your postDelayed Function after 5 miliseconds you can show this button to user like'
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
button.setVisibility(view.VISIBLE);
}
},500);
'and set it's click listener whatever you want'.
'Hope you get the solution.'
Related
I want run timer for about 30000 ms and up to 8 or more times each so here is my loop but it runs all timers at once after 30000ms
public void repeatTimerTask() {
repeat = 8; // need to run 30 sec timer for 8 times but one after one
startTimer(30000); // firsat timer for 30 sec
Handler handler = new Handler();
for (int a = 1; a<=repeat; a++) {
final int finalA = a;
handler.postDelayed(new Runnable() {
#Override
public void run() {
startTimer(30000);
}
}, 30000); // delay until to finish first timer for 30 sec
}
}
To run a timer for n seconds you can use CountDownTimer
Declare two varibales globbaly. One for number of times you want to repeat. and one to keep the count of repetaion.
private int NUM_REPEAT = 4;
private int REPEAT_COUNT = 0;
Then call this method wherever you want. One thing to note if you want to run this loop 5 times you have to give number of repeation 4. Cause to satrt this function you have to call it so that will not come in count.
private void startTimer() {
new CountDownTimer(3000, 1000) {
int secondsLeft = 0;
public void onTick(long ms) {
if (Math.round((float) ms / 1000.0f) != secondsLeft) {
secondsLeft = Math.round((float) ms / 1000.0f);
// resend_timer is a textview
resend_timer.setText("remaining time is "+secondsLeft);
;
}
}
public void onFinish() {
Log.d(TAG, "timer finished "+REPEAT_COUNT);
if (REPEAT_COUNT <= NUM_REPEAT) {
startTimer();
REPEAT_COUNT++;
}
}
}.start();
}
Please try the below code, and call 'startTimer' method where you first want to start your timer :
private int startTimerCount = 1, repeat = 8;
private void startTimer(){
// if startTimerCount is less than 8 than the handle will be created
if(startTimerCount <= repeat){
// this will create a handler which invokes startTimer method after 30 seconds
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
startTimer();
}
}, 30000);
// do what you want
Toast.makeText(this, "startTimer " + startTimerCount, Toast.LENGTH_SHORT).show();
}
startTimerCount++;
}
Below is a peice of code where on click the player will make their move by placing the X counter and then the computer will make their move by placing a O counter. The
only issue with this code currently is that when the player places their X counter, the O counter is placed as well at the same time. So it looks like both the player
and the computer has made their moves at the same time and that happens everytime the player makes their move.
What I want to ask, is it possible to include like a 2 second time delay so that the player will place their X and then after 2 seconds the computer will place their O?
Thanks in advance
#Override
public void onClick(View v) {
if (!((Button) v).getText().toString().equals("")) {
return;
}
if (playerOneMove) {
((Button) v).setText("X");
((Button) v).setTextColor(playerX);
computerMove();
}
}
private void computerMove() {
String[][] field = new String[3][3];
Random random = new Random(); //you may want to declare this as a class field
List<Button> emptyButtons = new ArrayList<>();
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
field[i][j] = buttons[i][j].getText().toString();
if (field[i][j].equals("")) {
emptyButtons.add(buttons[i][j]);
}
}
}
Button selectButton;
for (int i = 0; i < 3; i++) {
if (field[i][0].equals(field[i][1])
&& field[i][2].equals("")){
//prevent win/win on rows by selecting the correct button here
}
else if (field[i][0].equals(field[i][2])
&& field[i][1].equals("")){
//prevent win/win on rows by selecting the correct button here
}
else if (field[i][1].equals(field[i][2])
&& field[i][0].equals("")){
//prevent win/win on rows by selecting the correct button here
}
else {
selectButton = emptyButtons.get(random.nextInt(emptyButtons.size()));
}
selectButton.setText("O");
selectButton.setTextColor(playerO);
}
You could put computer logic inside handler or timer task: How to call a method after a delay in Android
but you also need some flag, that will block user placing X while you are waiting for computer to make it move.
i edited your onclick with the delay and i think you gonna need some sort of the flag wich blocks user until computer makes the move !
#Override
public void onClick(View v) {
if (!((Button) v).getText().toString().equals("")) {
return;
}
if (playerOneMove) {
((Button) v).setText("X");
((Button) v).setTextColor(playerX);
//2000 is your delay in mills format
v.postDelayed(new Runnable() {
#Override
public void run() {
computerMove();
}
},2000)
}
}
and i think it would be good idea to use some random number between 1sec to 3sec for delay and not the constant delay it creates better experience for user
You can check out the Handler and Runnable class in android. You can delayed the time of a method as required.
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
//Do something after 100ms
}
}, 100);
I want to change the background of an ImageView programatically, but inside a for / while loop on a separate thread. In my example, I have 3560 ImageViews in an ArrayList called 'lights'. I want to change each one's background inside a loop after a short delay, i.e. one changes every second.
ArrayList<ImageView> lights = new ArrayList<>();
int numberOfLights = 3560;
I originally used this code, but there is the problem that 'i' must be declared final as it is being called from an inner class, impossible if i need it for the for loop ...
Handler h = new Handler();
for( int i = 0; i < numberOfLights; i++) {
h.postDelayed(new Runnable() {
#Override
public void run() {
lights.get(i).setBackgroundResource(R.drawable.light_white);
}
}, 1000);
}
Therefore I tried using a global variable:
Handler h = new Handler();
counter = 0;
for( ; counter < numberOfLights; counter++) {
h.postDelayed(new Runnable() {
#Override
public void run() {
lights.get(counter).setBackgroundResource(R.drawable.light_white);
}
}, 1000);
}
It is as though this counter is completely ignored, h.postDelayed runs even when the counter is more than numberOfLights, I've tried just normal Threads with a Thread.sleep call, resulting in 'Only the original thread that created a view hierarchy can touch its views' and also used the runOnUiThread method but having no luck.
Any help is much appreciated.
Use the for each loop. It's way more elegant than the traditional loop and in this case you can make the local variable final
for(final ImageView light: lights) {
h.postDelayed(new Runnable() {
#Override
public void run() {
light.setBackgroundResource(R.drawable.light_white);
}
}, 1000);
}
also, define handler as
Handler h = new Handler(Looper.getMainLooper());
in order to run the code on UI thread
Just make a new variable:
final int iCopy = i;
Then use that in your Runnable.
Handler h = new Handler();
for( int i = 0; i < numberOfLights; i++) {
final int iCopy = i;
h.postDelayed(new Runnable() {
#Override
public void run() {
lights.get(iCopy).setBackgroundResource(R.drawable.light_white);
}
}, 1000);
}
This however may not avoid the IndexOutOfBoundsException if lights is being modified in the mean time. In that case a range check or making a copy of the array or light would solve your issue.
Is there any way of running a handler inside a loop?
I have this code but is not working as it does not wait for the loop but executes the code right way:
final Handler handler = new Handler();
final Runnable runnable = new Runnable() {
public void run() {
// need to do tasks on the UI thread
Log.d(TAG, "runn test");
//
for (int i = 1; i < 6; i++) {
handler.postDelayed(this, 5000);
}
}
};
// trigger first time
handler.postDelayed(runnable, 0);
Of course when I move the post delayed outside the loop works but it does not iterate nor execute the times I need:
final Handler handler = new Handler();
final Runnable runnable = new Runnable() {
public void run() {
// need to do tasks on the UI thread
Log.d(TAG, "runn test");
//
for (int i = 1; i < 6; i++) {
}
// works great! but it does not do what we need
handler.postDelayed(this, 5000);
}
};
// trigger first time
handler.postDelayed(runnable, 0);
SOLUTION FOUND:
I need to use asyntask along with Thread.sleep(5000) in the doInBackground method:
class ExecuteAsyncTask extends AsyncTask<Object, Void, String> {
//
protected String doInBackground(Object... task_idx) {
//
String param = (String) task_idx[0];
//
Log.d(TAG, "xxx - iter value started task idx: " + param);
// stop
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//
Log.d(TAG, "xxx - iter value done " + param);
return " done for task idx: " + param;
}
//
protected void onPostExecute(String result) {
Log.d(TAG, "xxx - task executed update ui controls: " + result);
}
}
for(int i = 0; i < 6; i ++){
//
new ExecuteAsyncTask().execute( String.valueOf(i) );
}
Instead of using a for loop, you can let the Runnable instance call itself for a specific number of times. These calls will be posted to UI thread queue so, keep that in mind. Also, since the delay is quite large, make sure the event is still needed when you trigger it next time.
The following code should do it:
final Handler handler = new Handler();
int count = 0;
final Runnable runnable = new Runnable() {
public void run() {
// need to do tasks on the UI thread
Log.d(TAG, "Run test count: " + count);
if (count++ < 5) {
handler.postDelayed(this, 5000);
}
}
};
// trigger first time
handler.post(runnable);
Here is a simple logic I made, without moving the for loop inside runnable.
for(int i = 1; i<=5; i++){
...
new Handler().postDelayed(() -> myFunctionToExecute() , i * 1000);
}
So whenever the loop iterates, it just extends the handler delay. And this way, you may achieve. I was searching for something similar, couldn't find anything, because in my case I already did the implementation of for loop, moving it inside the run() creates a mess
My solution to this problem if anyone has simmilar issues:
int count = 0;
public static void method(param1, param2, param3) {
Runnable r = () -> { //put method inside runnable
View view = listView.getChildAt(position); //action to be complete
if (view != null) { //if action is successfully complete
view.setSelected(true); //do something with this
} else { //do a looper
if (count < 10) { //limited looper to certain number
count++;
method(param1, param2, param3); //run the method again
}
};
Handler h = new Handler(); //create a new Handler and post above thread with it
h.postDelayed(r, 300);
}
Basically, I have created an if-else statement where else statement runs the same method with postDelayed() again for a limited number of trials.
This can be another solution
final Handler handler = new Handler();
Runnable runnable = new Runnable() {
int i;
public void run() {
for (i = 1; i < 6; i++) {
handler.postDelayed(new Runnable() {
#Override
public void run() {
// need to do tasks on the UI thread
Log.d(TAG, "runn test");
}
}, 0);
//Add some downtime
SystemClock.sleep(5000);
}
}
};
new Thread(runnable).start();
How can I make an android app that generates a random word every 1 second?
Here is my code:
new Timer().scheduleAtFixedRate(new TimerTask(){
public void run()
{
started = true;
word = "";
for (int i = 0; i < lenght+1; i++)
{
int j = rand.nextInt((max-min) + 1) + min;
word += tr.Translate(j);
}
txt.setText(word);
}
}, 0, 5000);
It seems that my app stops every time it must change the text of the TextView("txt"); how can I make this work?
Undoubtfully, run this within a Thread. Doing this, it will generate the words in background and once it already has, the main UI thread must just append the content to the txt instance.
new Thread(
new Runnable() {
public void run() {
// your stuff
}
}
).start()
To assign the result to the txt object, you'll probably be unable to do it within this thread. To do so, you'll need to declare a Handler in your Activity and use that handler within your thread, so it uses sendMessage() to the main Activity and the Activity just sets the text.
More on this here and here.
---- EDIT ----
As #FD_ says, there is another way to do the update without the use of a Handler. You would just need to call the runOnUiThread() method, something like this:
runOnUiThread(new Runnable() {
public void run() {
txt.setText(your_new_text);
}
});
Another way is using an AsyncTask, which is (talking vaguely) an "evolution" of a thread which makes a lot of stuff for you. More on AsyncTasks here.
---- EDIT ----
This would be one of the ways:
new Thread(
new Runnable() {
public void run() {
new Timer().scheduleAtFixedRate(new TimerTask() {
public void run() {
started = true;
word = "";
for (int i = 0; i < lenght+1; i++)
{
int j = rand.nextInt((max-min) + 1) + min;
word += tr.Translate(j);
}
// This will update your txt instance without the need of a Handler
runOnUiThread(new Runnable() {
public void run() {
txt.setText(word);
}
});
}
}, 0, 5000);
}
}).start();
try this:
int i = 0;
public void changeString() {
started = true;
word = "";
int j = rand.nextInt((max - min) + 1) + min;
word += tr.Translate(j);
txt.setText(word);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
if (i < lenght + 1) {
changeString();
i++;
}
}
}, 1000);
}
You can do this using timer as well
int i=0;
new Timer().scheduleAtFixedRate(new TimerTask(){
public void run()
{
started = true;
word = "";
int j = rand.nextInt((max-min) + 1) + min;
word += tr.Translate(j);
txt.setText(word);
i++
}
}, 0, 5000);
try the above. The mistake you were making is using a for loop inside run instead use loop run method it-self.