Hi I want to implement such behaviour:
Every one second I want to get a String from List and print it.
(actually I want my view to: setVisibility(View.Visible), but it's the same thing.
final Handler handler = new Handler();
for (String str : layoutsList) {
handler.postDelayed(new Runnable() {
#Override
public void run() {
Log.d("LevelOneFragment", "tick" + str);
i++;
}
}, 1000);
}
But this solution don't work.
How should I correctly do this?
Right now you are setting a delay for all work on the Handler at 1000ms. That means that each item of work will occur essentially at the same time, since the loop executes quickly.
Instead, why don't you try scheduling each item of work at an increasing delay, such as (i+1)*1000?
for (int i = 0; i < layoutsList.size(); i++) {
final String str = layoutsList.get(i);
handler.postDelayed(new Runnable() {
#Override
public void run() {
Log.d("LevelOneFragment", "tick" + str);
}
}, (i+1)*1000);
Why do you want to block the UI thread? :-(
for (String str : layoutsList) {
Log.d("LevelOneFragment", "tick" + str);
i++;
Thread.sleep(1000);
}
Related
I want to make an option in my application that if you click a button a counter will start and it will count (like 0++) and show the number until user stops it, so far I have this non working code
if (v == btn3) {
counter = 0;
scoreText.setBackgroundColor(Color.RED);
new Thread(new Runnable() {
public void run() {
while (counter < 1000 ) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
counter++;
}
}
}).start();
scoreText.setText(Integer.toString(counter));
}
Currently when i press the button, the text field only turns red and is set to 0, but I can't make it count
In my opinion setText method is outside loop. It could update text view after loop ends. Move it somewhere inside loop.
This should work as per your needs
if (v == btn3) {
counter = 0;
scoreText.setBackgroundColor(Color.RED);
new Thread(new Runnable() {
public void run() {
while (counter < 1000 ) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
#Override
public void run() {
scoreText.setText(Integer.toString(counter));
}
});
counter++;
}
}
}).start();
}
There is a a class called CountDownTimer which provides some useful functionality. In particular it provides an onTick() method with which you could update your text field at a desired interval.
You would need to create a CountDownTimer to count indefinitely, which you can do by restarting the timer in its onFinish() method, like in this question. But if you set the CountDownTimer for long enough, you probably would never need to restart it.
Something like this...
new CountDownTimer(<REALLY_BIG_NUMBER>, 500) {
int counter = 0;
public void onTick(long millisUntilFinished) {
scoreText.setText(counter++);
}
public void onFinish() {
start();
}
}.start();
I am having trouble delaying the method assign_backgrounds() within a for loop. I am trying to create a Simon says game, but instead of delaying and showing the next button that "Simon" presses, it shows all the buttons at once. Any help here would be greatly appreciated. Thanks.
boolean simonsTurn = true;
int x = 4;
int s;
int delay = 1000;
int array_values[] = new int[]{1,2,3,4};
public void simonSays() {
// running = true;
if (simonsTurn == true) {
go();
for (int i = 0; i < x; i++) {
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
go();
}
}, 1000);
}
}
}
public void go(){
s = random_int_between(0,3);
assign_backgrounds(array_values[s]);
}
public void assign_backgrounds( int array_values ){
Handler handler = new Handler();
if( array_values == 1){
button1_.invalidate();
button1_.setBackgroundResource(R.drawable.goatclicked);
button1_.refreshDrawableState();
handler.postDelayed(new Runnable(){
public void run(){
button1_.invalidate();
button1_.setBackgroundResource(R.drawable.goat);
button1_.refreshDrawableState();}}, 1000);
}
else if( array_values == 2){
button2_.invalidate();
button2_.setBackgroundResource(R.drawable.pigclicked);
button2_.refreshDrawableState();
handler.postDelayed(new Runnable(){
public void run(){
button2_.invalidate();
button2_.setBackgroundResource(R.drawable.pig);
button2_.refreshDrawableState();}}, 1000);
}
else if( array_values == 3){
button3_.invalidate();
button3_.setBackgroundResource(R.drawable.chickenclicked);
button3_.refreshDrawableState();
handler.postDelayed(new Runnable() {
public void run() {
button3_.invalidate();
button3_.setBackgroundResource(R.drawable.chicken);
button3_.refreshDrawableState();}}, 1000);
}
if( array_values == 4) {
button4_.invalidate();
button4_.setBackgroundResource(R.drawable.cowclicked);
button4_.refreshDrawableState();
handler.postDelayed(new Runnable(){
public void run(){
button4_.invalidate();
button4_.setBackgroundResource(R.drawable.cow);
button4_.refreshDrawableState();}}, 1000);
}
}
It's because you are creating handlers very fast and then they are all starting at the same time. You should look into how Handler's work and about Asyncronous/Background tasks.
Now back to your problem, you are calling the a loop and it is creating handlers all in a row and they are being created very fast (nanoseconds). They will then all launch 1 second from that creation time because of your postDelayed() call. This is why everything is popping up at the same time! All of these delay posts are being executed at almost the same time on concurrent background threads.
Instead of a for(int i,...) loop you want to have a global int i, just add it to the top of the file.
At the end of any of Simon's turn you'll want, inside of the if, else if statement inside assign_background (at the end of the Runnables, then you'll want to call go().
This might cause problems because you are trying to access the main thread from all these background threads. so you might have to call the function runOnMainUIThread() as a quick hack when you call the go function.
All in all, you are going to have some problems until you understand Handlers, Background Processes, and Threads. Definitely great knowledge to learn about and Android has solid documentation on it just FYI.
I've crated Log in screen, and if user mistake 3 times i want to show timer of 2 min. I want that timer to be visually shown on the screen. I'll try this code and it's work, but I don't know how to display timer on screen.
Handler handler = new Handler();
long waitingTime = 2 * 60 * 1000; // 2 min
handler.postDelayed(new Runnable() {
#Override
public void run()
{
//Do something after 2 min
}
}, waitingTime);
You need to have Handler called every second and update the UI during every pass. When you reach 2 mins you can cancel the handler.
Code should be like this:
final Handler handler = new Handler();
//class variable
count = 0;
handler.post(new Runnable() {
#Override
public void run() {
updateCounter(count++);
if(count < 120) {
handler.postDelayed(this, 1000);
}
}
});
And function to update counter:
private void updateCounter(final int count) {
runOnUiThread(new Runnable() {
#Override
public void run() {
// you have the seconds passed
// do what ever you want
}
});
}
you need use runOnUiThread(Runnable action)
I created a handler, to imitate timer task.
because TimerTask was acting differently on different tablets.
so I created this handler method.
in timer there was a method timerTask.cancel();
but how to stop this handler
it keeps on running even after the application is exited.
as you can see logs running even after back press.
Handler handler = new Handler();
public void recursivelycallHandler(){
handler.postDelayed(new Runnable() {
#Override
public void run() {
Log.d("handler is running", "true" + System.currentTimeMillis());
recursivelycallHandler();
}
}, 100);
}
There are 3 methods to do that ..
handler.removeCallbacks(Runnable r);
handler.removeCallbacksAndMessages(null);
handler.removeMessages(int what)
In your case first two seem feasible .. add any of the above method in ondestroy or on a listener to backpress..
By putting any condition
Handler handler = new Handler();
int i = 0;
Runnable myRunnable = new Runnable() {
#Override
public void run() {
Log.d("handler is running", "true" + System.currentTimeMillis());
if(i>5)
handler.removeCallback(myRunnable);
else{
i++;
handler.postDelayed(myRunnable, 100); // here is self calling
}
}
};
}
handler.postDelayed(myRunnable, 100);
Its recursive method but you can call the same Runnable object in run() instead of recursive method and remove that object when based on specific situation/condition
You can store flag (boolean var) to detect if you need to call for your handler and before exit app change this flag to false and stop calling handler.
you can do something like this below:
public void recursivelycallHandler(){
handler.postDelayed(new Runnable() {
#Override
public void run() {
Log.d("handler is running", "true" + System.currentTimeMillis());
if(YOUR_CONDITION){
recursivelycallHandler();
}
}
}, 100);
}
Hope you got my point.
feel free to comment.
just add isFinished to your run method:
handler.postDelayed(new Runnable() {
#Override
public void run() {
if (isFinished())
return;
Log.d("handler is running", "true" + System.currentTimeMillis());
recursivelycallHandler();
}
}, 100);
I'm emulating a Frame Animation; I have it all working spare one issue.
I have a for loop in which, on every iteration, it changes the Image of an ImageView after a delay.
for(int i = 1; i <13; i++){
if (stop== false){
String imgName = "b"+ Integer.toString(i);
id = getResources().getIdentifier(imgName, "drawable", getPackageName());
Handler handlerTimer = new Handler();
handlerTimer.postDelayed(new Runnable(){
public void run() {
view.setImageDrawable((getResources().getDrawable(id)));
}}, 300);
}
}
The issue is that run() doesn't refresh on every iteration; it only works once.
How can I refresh or make a new run()?
I'm open to any other way to do this.
Any advice would be appreciated.
Step #1: Define the Runnable as a data member of your activity (or wherever this code resides)
Step #2: Dump the Handler, as you don't need it -- postDelayed() is implemented on View as well
Step #3: Create a helper method that does the postDelayed() call -- I'll refer to that method as foo() here -- and call foo() where you right not call postDelayed()
Step #4: In run() of the Runnable, call foo() again to reschedule the Runnable for another delay period
Give this a try, if it doesnt work then ill try somthing else:
for(int i = 1; i <13; i++)
{
if (stop== false)
{
String imgName = "b"+ Integer.toString(i);
id = getResources().getIdentifier(imgName, "drawable", getPackageName());
Handler handlerTimer = new Handler();
handlerTimer.postDelayed(new Runnable(){
public void run() {
view.setImageDrawable((getResources().getDrawable(id)));
view.invalidate();
}}, 300);
}
}
invalidate() should cause your view to be repainted and you should get the desired effect. Hope this helps!
This is the Thread example:
public class Main implements Runnable
{
public Main()
{
Thread thread = new Thread(this);
thread.start();
//new Thread starts at run()
}
public void run()
{
String imgName = "b"+ Integer.toString(i);
id = getResources().getIdentifier(imgName, "drawable", getPackageName());
try
{
for(int i = 1; i <13&!stop; i++)
{
view.setImageDrawable((getResources().getDrawable(id)));
Thread.sleep(300);
}
}catch(Exception e){e.printStackTrace();}
}
public static void main(String args[]){new Main();}
}
if you need anything else at all, just let me know!