Java(Android) stuck in while loop - java

when I run my app it will continuously be stuck in a while loop. It should leave the while loop when a button is pressed, however even after pressing a button it continues to loop.
View.OnClickListener listener11 = new View.OnClickListener() {
#Override
public void onClick(View view) {
temp1 = button[0];
temp3 = button[0].getBackground();
state++;
}
};
while(state == 0) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
button[0].setOnClickListener(listener11);
}
variable:
state is an int temp1 is a button temp3 is a Drawable
the delay is there because I actually have 20 buttons and I have the setOnClickListeners for all the buttons inside that while loop so I think it causes it to crash without the delay. Another question would be is it possible to have the setOnClickListeners outside the while loop but still be able to check for button clicks inside the loop?

The problem is you are pressing the button while the thread is in a sleeping state causing the event to not be triggered and therefor the state to never change.

You should remove the while loop and just set all the listeners in a for loop:
for(int i = 0; i< button.length; i++) {
button[0].setTag(i);
button[0].setOnClickListener(listener11);
}
And then change your listener to be something like:
private boolean firstClick = true;
View.OnClickListener listener11 = new View.OnClickListener() {
#Override
public void onClick(View view) {
if(firstClick) {
firstClick = false;
temp1 = button[(int)view.getTag()];
} else {
temp2 = button[(int)view.getTag()];
}
}
};

I'm not sure exactly what the code is supposed to be doing because I have no idea of the context, but I think think you could remove the while loop altogether:
// initialize the listener
View.OnClickListener listener11 = new View.OnClickListener() {
#Override
public void onClick(View view) {
// add code that runs when button is clicked here
}
};
// now that we have the listener all set up we add it to the button, at which point it just keeps listening for you, no need to put the thread to sleep
button[0].setOnClickListener(listener11);
UPDATE:
So because you want to see if the second value matches the first value you could use a helper method:
private String firstValue = "";
public boolean isMatch(String mostRecentValue) {
boolean match = false;
if (firstValue.isEmpty()) {
firstValue = mostRecentValue;
} else {
match = firstValue.equals(mostRecentValue);
firstValue = "";
}
return match;
}
This method takes a value and if it is the first click the value is saved, if it is the second click it compares it with the first click and then resets the method. A boolean is returned false for no match, and true for a match. Call this method from within the onClick() method and pass in the buttons value. I've used String as an example value but you could use any object type.

I think you might be misunderstanding what setOnClickListener is doing. It's not handling the click, it is setting up the click handler. The line button[0].setOnClickListener(listener11); would be part of your activity initialisation and then not called again.
The reason you get stuck is because the main thread is busy in the while loop and isn't given an opportunity to process click events. Click events are handled on the main thread but only when it's not already busy doing something. In this case, it's forever busy in the while loop. For example, if the main thread was processing a method that would take 10 seconds to complete and you tap on a button 3 seconds into it, the button press wouldn't be handled for another 7 seconds. At which point, the previously set listener11 would be executed.
What you seem to be trying to achieve is already handled by the Looper. You need to be thinking in terms of event handling. So in other words, all your logic needs to go in listener11 or something similar.

Related

How to wait on a button for user input in order to set a variable

I am writing a class that has certain variables that don't need to be set except in certain fringe cases. As such, I am working on writing a requestVariable() method that asks for user input to set that variable when it is needed. However, I am struggling to figure out how to wait for that input before moving on. Let me show you what I have.
SkillApplication AR_D_Atk_Def_1_app = (Unit) -> {
if (Unit.getAttackStatus() != com.codecademy.myapplication.Unit.AttackStatus.DEFENDER) {
return;
}
else {
// Make sure structuresAR is set
Unit.setStructuresAR(requestVariable( /* some parameters */ );
int X;
if (Unit.getStructuresAR() >= 5) {
X = 4;
}
else if (Unit.getStructuresAR() == 4) {
X = 3;
}
else if (Unit.getStructuresAR() == 3) {
X = 2;
}
else {
X = 1;
}
Unit.addCombatAtk(X);
Unit.addCombatDef(X);
}
};
This is a lambda function for a certain skill's application. If this skill needs to be applied, it will run this lambda function. This is one of the fringe cases where the member "structuresAR" of Unit needs to be used. It's very rarely used, and rather than having the user set it every time, I have it set in this lambda function.
VariableRequest<Integer> requestInteger = (VariableRequest<Integer>) (questionMessage, choices, layout) -> {
final Integer[] retVal = new Integer[1];
TextView questionView = new TextView(layout.getContext());
questionView.setText(questionMessage);
EditText textEntry = new EditText(layout.getContext());
textEntry.setInputType(InputType.TYPE_CLASS_NUMBER);
Button submitButton = new Button(layout.getContext());
submitButton.setText("Submit");
layout.addView(questionView);
layout.addView(textEntry);
layout.addView(submitButton);
submitButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
retVal[0] = Integer.parseInt(String.valueOf(textEntry.getText()));
}
});
};
Here's what I have written so far for that function. It sets a question, options, and submit button to a layout that updates a return value with what is in the entry box when a button is clicked.
This problem is, this just keeps going. The rest of whatever I've written will be run while the onClickListener is still there, and I don't know how to wait until that's been clicked. I'm coming from C++ knowledge where just writing cin >> variable would pause and wait for you to enter. I'm trying to replicate that with a button.
There's also other problems I can spot with this such as getting the layout from inside a static method, but I struggle to come up with another method as I'm very new to Android development.

onClick is not working until I comment the while Loop inside my function

I have a function goClicked which is a onClick method of "Go" button, but when clicking the button, the function is not executed (I am able to say this because the toast is not showing).
But if I comment the while loop then click on the "Go" button, the function is executed (the toast is appearing).
public void goClicked(View view) {
afterGoPressed();
Toast.makeText(MainActivity.this,"pressed",Toast.LENGTH_SHORT).show();
countDown();
correctCount = 0;
totalCount = 0;
TextView time = (TextView) findViewById(R.id.time);
String timetext = time.getText().toString();
while (!timetext.equals("0")) {
int sum = generateQuestion();
pickOption = generateOptions(sum);
}
}
By putting a tight loop like that into your code the Event Dispatch Thread (EDT) is "starved" and so the GUI never gets a chance to do anything.
A simple workaround would be add a bit of a sleep in the loop to let the EDT have a turn. But you really need to do a bit more research into how to do GUI programming.
As it stands the code looks like an infinite loop because the timetext variable used in the loop condition does not change inside the loop. timetext is presumably supposed to change in reaction to GUI events. If the GUI is starved and so doesn't get to run then timetext never changes.
I think you're dealing with an infinite loop.
If when you create the variable timetext the text contained in time is not 0, the variable timetext will never be 0, hence the condition to exit the loop is never met.
public void goClicked(View view) {
afterGoPressed();
Toast.makeText(MainActivity.this,"pressed",Toast.LENGTH_SHORT).show();
countDown();
correctCount = 0;
totalCount = 0;
TextView time = (TextView) findViewById(R.id.time);
String timetext = time.getText().toString(); // <--- this will never change
while (!timetext.equals("0")) {
int sum = generateQuestion();
pickOption = generateOptions(sum);
}
}
Sorry, I know this doesn't offer much of a practical solution to your issue. Maybe if you let us know what you're trying to achieve with that loop we can help a little better.
But for all I know, if you block a thread inside of the public void onClick(View view) method of a View.OnClickListener instance (either by making it sleep with Thread.sleep() or by running an infinite loop), it will also freeze the rest of your app until the onClick(View view) method finishes. That's why you can't even see the Toast appear, although it's before the while loop. Because the main Thread was notified that there has been a click event, but the response from that event is never arriving.

Updating textView in Android Studio

I have a textView set up on my main activity, and a button. When I click the button, I'd like the textView to start updating it's value based on the code below. However, this doesn't work and the problem is the loop. Can someone explain why? I am new to Java and Android Development
button2 = (Button) findViewById(R.id.button);
button2.setOnClickListener(new OnClickListener() {
TextView textView = (TextView)findViewById(R.id.refView);
public void onClick(View arg0) {
for(i=1;i<1;i++){
i = i + 1;
textView.setText(String.valueOf(i)+"hello");
}
}
});
Thank You
Try this:
TextView textView = (TextView)findViewById(R.id.refView);
button2.setOnClickListener(new View.OnClickListener() {
int i = 0;
public void onClick(View arg0) {
i = i + 1;
textView.setText(String.valueOf(i)+"hello");
}
});
Your for loop conditions were wrong.
for(i=1;i<1;i++) won't even start, because 1<1 is already met.
Initiate count variable i before onClick and then update it before click and set new text with updated i.
Not sure what exactly you want to happen. But, you can get rid of this line
i = i + 1;
because the i++ already increments i by 1 with each iteration of the for loop.
Second, since i starts off at 1 and you want the loop to run while i<1, it will never enter the loop. It is never less than 1.
Third, if the conditions were different, say
for (int i=0; i<10; i++)
it will run through the loop so fast that you won't even recognize a change.

How to control a loop using a button?

I am a beginner in java, I want to know is there any possible way to control a loop by clicking a button? I am creating a GUI, and it's supposed to run 10 times in the loop. Is there a way that I could have a button on the screen so that when the user presses, then it goes to the next iteration? Because currently everything just runs and executes once.
In your java class, you should define an attribute and each time you click on the button you add 1 to this attribute and do the action.
define an attribute in your class;
public int i = 0;
and create a button to be clicked on:
private void clickMeButtonActionPerformed(java.awt.event.ActionEvent evt) {
// code your action here:
this.i++;
}
You could have the loop wait for the button click, and then once it loops 10 times break the loop.
You can use javaFX it's gonna replace javaswing very soon anyways plus it's cooler.
import javafx.scene.control.button
Button button = new Button("control");
int i = 0;
button.setOnAction(new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent e) {
i++;
label.setText("i increased");
}
});

Stopping a for loop with a button

I am trying to stop a for loop that is initiated by pressing a button. The only problem I have found is that the application is literally non-responsive once the start button is pressed. How would I go about making the stop button? At the moment the only way I can stop the application outside of my IDE is to go into task manager and forcibly delete it.
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
String L = "Hello";
int Num = Integer.parseInt(m1.getText());
int Num2 = Integer.parseInt(m2.getText());
nu = Num;
for (int kk = nu; nu > 0; nu--) {
if (O1.isSelected()) {
for (int num3 = nu; nu > 0; nu--) {
try {
try {
Thread.sleep(Num2 * 1000);
} catch (InterruptedException ex) {}
Robot robot = new Robot();
robot.keyPress(KeyEvent.VK_F);
} catch (AWTException e) {
e.printStackTrace();
}
}
}
}
This is the code I have, I have been looking around and I think I need to use the SwingWorker class. I am not sure how to implement it though.
Have you put your loop inside the button action handler?
If so remove it and put it in a thread. Else it will block the EDT and app will become unresponsive. Use buttons only to trigger start and stop.
Without code it is hard to determine, but you are probably performing the loop on AWT thread, hence your UI is blocked and you can not press a button.
You should move your endless loop to another Thread, and then the button will work
You are entering in an infinite loop any how. I would suggest to put your loop in a separate thread and when you want to stop it just interrupt that thread on button click.
Move the code into a dedicated thread and use a variable check to end the loop externally.
The first problem is that you're performing this loop inside the Event Dispatch Thread (EDT). This is a thread which is dedicated to handling the user interface. Since you are looping and sleeping in this thread, it is unavailable to handle any other user interactions. So effectively you are locking yourself out of your own program.
The proper way to shut this down is to create a shutdown() method on the loop which will modify a variable that is checked in each iteration of the loop. Then, when you want to shut it down, you just call this method on the Runnable and the loop shuts down.
public class KeyPressRunnable implements Runnable {
private boolean isRunning = true;
public void shutdown() {
this.isRunning = false;
}
#Override
public void run() {
// put your loop in here, and include this code in the loop:
if (!this.isRunning) break;
}
}

Categories

Resources