Handler - why is my runnable not executing? - java

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.

Related

I need someone to explain for me this java code

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);

How do I delay a method in a for loop in java?

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.

Move image up they y-axis in eclipse

I am making a game for androids using eclipse and I had some trouble trying to figure this out. I already have 2 images on my layout and I just want to figure out how to make them move one unit up the y axis with a timer that is repeatedly. Thanks alot for any help appreciate it!
You can do something like
final int interval = 1000; // one second
View myView = ...;
Handler handler = new Handler();
Runnable runnable = new Runnable() {
#Override
public void run() {
// Do work
myView.setY(myView.getY() + 1);
handler.postDelayed(this, interval);
}
handler.post(runnable);

Using threads in a Java FX UI that should return a result

I am probably missing something here, but I'll try and explain what I want to achieve and then someone please tell me that I am doing it wrong(which I am :) ) and point me in the right direction?
I am using JavaFX 2.0, but I think this problem would lend itself to Swing, or any UI framework.
I want to develope a simple splash screen for my application, when the splash screen starts, I want to have a message label that will be used to update a user on whats happening, in regards to configuring up the back end of the application. My application start up has 2 steps, the first step uses Spring to initialise the Application Context, which in turn initialises the DB (JPA 2.0/Hibernate/etc). The second part of my application start up process will query the DB for the initial data which will be used to populate the UI. Both these steps need to be complete before I can close the splash screen, and between each step I want to update the label in the splash screen to let a user know which stage is being done at that time.
I have broken this down into the following simple program which uses JavaFX and a button, when the button is pressed a new thread is created, that starts another class, which just performs some count to an abitary value, and then another another thread is created to simlate the second step of the start up process, But my issue is here that the second thread attempts to run before the first thread has finished, and as a result runs into a NPE.
Below is a breakdown of some simple code that highlights this issue:
public class Test extends Application
{
private LongTester lt;
public static void main(String[] args)
{
launch(args);
}
#Override
public void start(Stage primaryStage)
{
Button btn = new Button();
final Label lblText = new Label("Starting");
btn.setText("Say 'Hello World'");
btn.setOnAction(new EventHandler<ActionEvent>()
{
#Override
public void handle(ActionEvent event)
{
new Thread(new ConstructorRunnable()).start();
lblText.setText("More Loading?");
new Thread(new MethodRunnable()).start();
lblText.setText("Finished");
}
});
HBox root = new HBox();
root.getChildren().add(btn);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
private class ConstructorRunnable implements Runnable
{
#Override
public void run()
{
lt = new LongTester();
}
}
private class MethodRunnable implements Runnable
{
#Override
public void run()
{
lt.countAgain();
}
}
private class LongTester
{
public LongTester()
{
for (int idx = 0; idx < 1000000; idx++)
{
System.out.println("Constructor: " + idx);
}
}
public Boolean countAgain()
{
for (int idx = 0; idx < 1000000; idx++)
{
System.out.println("Method: " + idx);
}
return Boolean.TRUE;
}
}
}
Can anyone point out my mistake?
I'd advise using a Task to execute your startup tasks and message progress back to your splash screen (similar to the approach in this sample created for a prior stackoverflow question on splash screens). If you want stuff in your task to run sequentially, just use one thread for the task rather than two.
Sample code for your task might look something like:
final Task<Data> initTask = new Task() {
#Override protected Data call() throws InterruptedException {
updateMessage("Initializing Application");
MyApp.initializeAppContext();
updateMessage("Loading Data");
Data data = DB.loadData();
updateMessage("Data Loaded");
return data;
}
showSplash(initStage, initTask);
new Thread(initTask).start();
showMainStage(initTask.valueProperty());
To fix your problem, you can use a CountDownLatch
This can be used the following way:
private class ConstructorRunnable implements Runnable {
CountDownLatch gate_ = null;
public ConstructorRunnable(CountDownLatch gate){
gate_ = gate;
}
#Override
public void run() {
lt = new LongTester();
gate_.countDown(); // Signal the second thread to start
}
}
private class MethodRunnable implements Runnable{
CountDownLatch gate_ = null;
public MethodRunnable(CountDownLatch gate){
gate_ = gate;
}
#Override
public void run(){
CountDownLatch.await(); // Wait for the first thread to finish
lt.countAgain();
}
}
This can now be used like this:
CountDownLatch gate = new CountDownLatch(1);
new Thread(new ConstructorRunnable(gate)).start();
lblText.setText("More Loading?");
new Thread(new MethodRunnable(gate)).start();
lblText.setText("Finished");
On a side note: as your tasks are sequential, why is there a need for having several threads? Threads are made to run multiple tasks running in parallel and your case does not make a use case for threads as these operations are sequential

Creating Unique postDelayed Runnables in a Loop

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!

Categories

Resources