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!
Related
I'm solving an exercise for my university and there is this code in my pdf that my supposed to use to delay the change of the colour of the text on a button, i don't understand how it exactly works so please can someone explain it
HandlerThread handlerThread = new HandlerThread("showText");
handlerThread.start();
Handler handler = new Handler(handlerThread.getLooper());
Runnable runnable = new Runnable() {
int i = 0;
#Override
public void run() {
i++;
handler.postDelayed(this, 1000);
if (i > 1)
button.setTextColor(getResources().getColor(android.R.color.transparent));
}
};
handler.post(runnable);
This code is in obscure way causing that Runnable to be called with the delay of 1s (every second) because it reschedules itself each time. The int i is guarding button.setTextColor from executing the first the.
This code is however very messy, the way it should be done is as follows:
Runnable runnable = new Runnable() {
#Override
public void run() {
button.setTextColor(getResources().getColor(android.R.color.transparent));
}
};
handler.postDelayed(runnable, 1000);
or with lambda expression just as following:
handler.postDelayed(() -> button.setTextColor(getResources().getColor(android.R.color.transparent)), 1000);
I have a simple class which has a thread in it. Whenever user clicks on a button, I want to run the thread. Everything works great, except that whenever I click on the button while the thread is already running, my onTouch executes only after the thread has finished executing.
..
MyTouchAnimatorClass touchAnimatorClass = new MyTouchAnimatorClass();
view.setOnClickListener( new View.OnClickListener()
{
#Override
public void onClick( View view )
{
touchAnimatorClass.onTouch();
}
});
..
And my class with the thread:
Class MyTouchAnimatorClass
{
private boolean threadRunning = false;
public void onTouch() // <-- only executes AFTER the thread is complete
{
if( !threadRunning )
animate();
}
private void animate()
{
threadRunning = true;
Runnable r = new Runnable()
{
#Override
public void run()
{
activity.runOnUiThread(new Runnable()
{
#Override
public void run()
{
int i=0;
boolean doBreak = false;
while( true )
{
i+=1;
if( i == 100 )
break;
}
}
}
}
}
new Thread( r ).start();
threadRunning = false;
}
}
I can't understand why this is happening, isn't the Runnable running in its own thread? Any suggestions please? Thank you!
EDIT:
I tried using
new Thread( r ).start();
Instead of:
r.run();
But unfortunately the same problem persists:
If I click the button the second time (while the thread is still running from the first click), it should execute onTouch, but shouldn't execute animate() since it is still running from the previous click.
What actually happens: The touch is non response until the thread from the first click has finished executing. Then onTouch triggers (even though I pressed it few seconds ago) and a new thread is started again.
If I press the button 10 times quickly, it will do 10 loops in a row, instead of doing one and blocking the others.
activity.runOnUiThread is asking the Android system to run this Runnable on the UI thread.
You can rather do new Thread(r).start();
Like this:
private void animate()
{
threadRunning = true;
//Define the work as a Runnable
Runnable r = new Runnable()
{
#Override
public void run()
{
int i=0;
//boolean doBreak = false; //Not used
while( true )
{
i+=1;
if( i == 100 )
break;
}
threadRunning = false; //Just before leaving
}
}
//Give that work to a new thread and start the thread
new Thread(r).run();
}
Runnable isn't a thread, is just a set of instructions to be executed in a thread
in order to achieve what you want you need to do
new Thread(r).start(); at end of your code
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);
}
I have a runnable that I want to execute 4 times a second. Here is my runnable:
shoot = new Runnable() {
#Override
public void run() {
//Add bullet
parts.add(new Part(1, (int)(screenWidth*.01),
Part.TYPE_CIRCLE, (int)parts.get(activeShooter).center.x,
(int)parts.get(activeShooter).center.y));
parts.get(parts.size()-1).x_vel = (int)(Math.cos(parts.get(activeShooter).rotation)*bulletSpeed);
parts.get(parts.size()-1).y_vel = (int)(-Math.sin(parts.get(activeShooter).rotation)*bulletSpeed);
activeShooter = (activeShooter == numShooters) ? 0 : activeShooter + 1;
shooter.postDelayed(shoot, 250);
}
};
And here is my initial handler setup:
private void startBullets(){
Looper.prepare();
shooter = new Handler();
shooter.postDelayed(shoot, 250);
}
In all my other projects, I didn't have to call Looper.prepare but it throws an exception if I don't in this project. I don't know why. I basically copied a working code from another project (one that didn't require me to call Looper.prepare()). Can anyone see why my runnable isn't executing?
private void startBullets(){
shooter = new Handler();
shooter.postDelayed(shoot, 250);
}
Make sure you quit your Looper via Looper.quit() when you're done.
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.