I have an if statement which checks if three slots are finished. If it is, the timer should stop, but the code is not running for some reason. I have seen a post similar to this If-condition never executes despite correct condition, however their solution solved nothing.
Here is my code:
Stop function
public void stop(ImageSwitcher slot){
slotOneFinished = (slot.equals(slotOne));
slotTwoFinished = (slot.equals(slotTwo));
slotThreeFinished = (slot.equals(slotThree));
if (slotOneFinished&&slotTwoFinished&&slotThreeFinished){
//not running
Toast.makeText(MainActivity.this, "Running",Toast.LENGTH_SHORT).show();
checkWin(getFruits());
timer.cancel();
timer = null;
}
}
Timer
private Timer timer;
TimerTask timerTask = new TimerTask() {
#Override
public void run() {
runOnUiThread(new TimerTask() {
#Override
public void run() {
if (!slotOneFinished){
animate(randomSwitchCount(), slotOne);
}
if (!slotTwoFinished) {
animate(randomSwitchCount(), slotTwo);
}
if (!slotThreeFinished) {
animate(randomSwitchCount(), slotThree);
}
}
});
}
};
Animate function
public void animate(final int maxCount, final ImageSwitcher slot) {
i++;
if (i<maxCount){
Animation in = AnimationUtils.loadAnimation(this, R.anim.new_slot_item_in);
Animation out = AnimationUtils.loadAnimation(this, R.anim.old_item_out);
slot.setInAnimation(in);
slot.setOutAnimation(out);
int fruit = randomFruit();
slot.setTag(fruit);
slot.setImageResource(fruit);
}else {
stop(slot);
}
}
Using == did nothing as well.
Thanks for your help,
PiNet
This condition can never be true, assuming that equals() is implemented in the canonical way, and slotOne, slotTwo, and slotThree are 3 distinct objects:
if (slotOneFinished&&slotTwoFinished&&slotThreeFinished)
Looks like you had a mistaken assumption about the scope of the variables. You can probably fix this by using a condition like this, instead:
if( slot == slotOne )
slotOneFinished = true;
...and so forth.
The Android Studio debugger is your friend.
Related
I have a slot machine code where it rolls through random fruits with a maxCount for each slot. Once the maxCount is reached that slot will stop. However, sometimes the slot, stop method is called more than once. Any ideas?
TimerTask
TimerTask task = new TimerTask() {
#Override
public void run() {
runOnUiThread(new TimerTask() {
#Override
public void run() {
count++;
if (!slotOneFinished){
animate(randomSwitchCount(), slotOne, count);
}
if (!slotTwoFinished) {
animate(randomSwitchCount(), slotTwo,count);
}
if (!slotThreeFinished) {
animate(randomSwitchCount(), slotThree,count);
}
}
});
}
};
Stop function
public void stop(ImageSwitcher slot){
if (slot.equals(slotOne)){
slotOneFinished=true;
Toast.makeText(MainActivity.this, "1",Toast.LENGTH_SHORT).show();
}
if (slot.equals(slotTwo)){
slotTwoFinished=true;
Toast.makeText(MainActivity.this, "2",Toast.LENGTH_SHORT).show();
}
if (slot.equals(slotThree)){
slotThreeFinished=true;
Toast.makeText(MainActivity.this, "3",Toast.LENGTH_SHORT).show();
}
if (slotOneFinished&&slotTwoFinished&&slotThreeFinished){
executor.shutdown();
executor=null;
roll.setEnabled(true);
checkWin(getFruits());
slotOneFinished=false;
slotTwoFinished=false;
slotThreeFinished=false;
}
}
Start function
public void start() {
if(executor==null) {
count =0;
executor = Executors.newSingleThreadScheduledExecutor();
executor.scheduleAtFixedRate(task,10,200,TimeUnit.MILLISECONDS);
}
}
Animate function
public void animate(final int maxCount, final ImageSwitcher slot, int i) {
if (i<maxCount){
Animation in = AnimationUtils.loadAnimation(this, R.anim.new_slot_item_in);
Animation out = AnimationUtils.loadAnimation(this, R.anim.old_item_out);
slot.setInAnimation(in);
slot.setOutAnimation(out);
int fruit = randomFruit();
slot.setTag(fruit);
slot.setImageResource(fruit);
}else {
stop(slot);
}
}
Count is set to 0 at the beginning of the program and randomSwitchCount() returns a random number between 10 and 40. I am assuming that I do not have the correct order of running some code. I used the toast messages to highlight my problem during testing. If there is anything else which you see wrong with my functions & logic, I am all ears.
Thanks,
Pi Net
The timer was scheduled to run one more time. But isFinished was set to false for every slot just before the timer ran so the condition became true. Instead, I set them to false only when the roll button was finished so that the time was in sync with the win detection.
I created one handler to repeat a task repeatedly and I also want to destroy it within that handler once a condition has been met.
pinHandler = new Handler();
Now I created two functions separately to start and stop the task.
void startRepeatingPins() {
mPinSetter.run();
}
Runnable mPinSetter = new Runnable() {
#Override
public void run() {
try{
System.out.println("PinIndwx count is :"+pinIndexCount);
if(pinIndexCount==(plist.size()-1))
{
stopUpdatingPins();
pinIndexCount=0;
//pinHandler.removeCallbacks(mPinSetter);
System.out.println("Handler stopped by itself.");
}
else
{
updatePoint(plist.get(pinIndexCount));
pinIndexCount++;
}
}
finally {
pinHandler.postDelayed(mPinSetter, pinInterval);
}
}
};
private void stopUpdatingPins()
{
pinIndexCount=0;
pinHandler.removeCallbacks(mPinSetter);
System.out.println("Called the stop function.");
}
Now, the issue is that, if I call the stopUpdatingPins function , the handler stops but when I try to stop it automatically from within the handler, it just doesn't stop. Although the stopUpdatingPins function does get called.
Change You startRepeatingPins() like this, You should not directly call the run. If your run like this then there is no point of removing this from Handler. So attach Runnable with Handler.
void startRepeatingPins() {
pinHandler.post(mPinSetter);
}
You added post delay in finally that means you are stopping at first if loop and starting again in finally, So it's never stopping. So Change your runnable like this,
Runnable mPinSetter = new Runnable() {
#Override
public void run() {
System.out.println("PinIndwx count is :"+pinIndexCount);
if(pinIndexCount==(plist.size()-1))
{
stopUpdatingPins();
pinIndexCount=0;
//pinHandler.removeCallbacks(mPinSetter);
System.out.println("Handler stopped by itself.");
}
else
{
updatePoint(plist.get(pinIndexCount));
pinIndexCount++;
pinHandler.postDelayed(mPinSetter, pinInterval);
}
}
};
I've got a listView that gets populated from a server. In the onClick of the ListItem, I display a button for a x number of seconds and I make it invisible again. How can I reset the time every time the onClick is called?
Here is my listItem onClick:
private void displayInCallButton() {
mButton.setEnabled(true);
if (canDisplayInCallControlls) {
canDisplayInCallControlls = false;
fadeInAnimation(mButton);
mButton.setEnabled(true);
mFrontView.postDelayed(new Runnable() {
public void run() {
fadeOutAnimation(mButton);
mButton.setEnabled(false);
hasAnimationEnded = true;
canDisplayInCallControlls = true;
}
}, 5000);
}
}
Thank you in advance.
You have to remove the callbacks and set it once again with the new one with the reset time.
first, set the call back like
Runnable myRunnable = new Runnable() {
#Override
public void run() {
fadeOutAnimation(mButton);
mButton.setEnabled(false);
hasAnimationEnded = true;
canDisplayInCallControlls = true;
}
};
then set it to mFrontView like,
mFrontView.postDelayed(myRunnable,5000)
If you want to reset, do it like
mFrontView.removeCallbacks(myRunnable);
mFrontView.postDelayed(myRunnable, 2000);
How can I reset the time every time the onClick is called?
There is no built-in mechanism to accomplish that.
You can, however, keep a reference to the Runnable you post, remove it and then repost it again to restart at the original delay.
The result would look somewhat like this in its most simple form:
Runnable mDelayedRunnable = new Runnable() {
#Override public void run() {
fadeOutAnimation(mButton);
mButton.setEnabled(false);
hasAnimationEnded = true;
canDisplayInCallControlls = true;
}
};
private void displayInCallButton() {
mButton.setEnabled(true);
if (canDisplayInCallControlls) {
canDisplayInCallControlls = false;
fadeInAnimation(mButton);
mButton.setEnabled(true);
mFrontView.removeCallbacks(mDelayedRunnable);
mFrontView.postDelayed(mDelayedRunnable, 5000);
}
}
You can safely call removeCallbacks() with a Runnable that was never posted in the first place (or even null).
If you don't want to keep an explicit reference to the Runnable, you could also opt to tag the view with it. Just don't forget to clean up on i.e. orientation changes and the like.
I am developing an android game where I have a loop (not a game loop). This loop reacts if one of my booleans is changed. The problem is that when the boolean is changed, it calls the void inside the loop untill the app crashes of an overload. The void I am calling is suronded with a try-catch and it has to be, unless I have to remake the rest of my game. The code for the loop is like so:
private void listenerVoid(){
int timeBetweenChecks = 100;
final Handler h = new Handler();
h.postDelayed(new Runnable(){
public void run(){
//Do something if myBool returns true, otherwise loop again
if (myBool==false){
listenerVoid();
} else {
//Check if the listener has reacted to a change before
if(firstStart!=false){
firstStart = false;
theTryCatchVoid();
Log.i("MyClass","Boolean is changed");
}
else{
//Already started
Log.i("MyClass","Already started");
}
}
}
}, timeBetweenChecks);
};
And my try-catch void is similar to this:
private void tryCatchVoid(){
try{
//Try to do something that soemtimes causes a crash
}
catch(Exception e){
//Do nothing
}
}
I can not increase the timeBetweenChecks time, because it will then cause a long waiting time in my game. How can I make the tryCatchVoid only be called once?
I have an app that shows a disclaimer at the beginning of the program. I want a button to remain invisible for a set amount of time, and then become visible.
I set up a thread that sleeps for 5 seconds, and then tries to make the button visible. However ,I get this error when I execute my code:
08-02 21:34:07.868: ERROR/AndroidRuntime(1401): android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
How can I count 5 seconds, and then make the button visible?
THanks.
Thread splashTread = new Thread() {
#Override
public void run() {
try {
int waited = 0;
while(_active && (!_ok2)) {
sleep(100);
if(_active) {
waited += 100;
if(waited >= _splashTime)
{
turnButtonOn();
}
}
}
} catch(InterruptedException e) {
// do nothing
} finally {
finish();
startActivity(new Intent("com.lba.mixer.Choose"));
}
};
splashTread.start();
public static void turnButtonOn() {
okButton.setVisibility(View.VISIBLE);
}
The problem is that you're not in the UI thread when you call okButton.setVisibility(View.VISIBLE);, since you create and run your own thread. What you have to do is get your button's handler and set the visibility through the UI thread that you get via the handler.
So instead of
okButton.setVisibility(View.VISIBLE)
you should do
okButton.getHandler().post(new Runnable() {
public void run() {
okButton.setVisibility(View.VISIBLE);
}
});
I found this to be a much simpler solution. Visibility on 7 second delay
continuebutton.setVisibility(View.INVISIBLE);
continuebutton.postDelayed(new Runnable() {
public void run() {
continuebutton.setVisibility(View.VISIBLE);
}
}, 7000);
I found this a Better solution to the problem
(button id = but_resend)
define handler
private Handler handler;
call function in extend class
showButtons();
define after class
private void showButtons() {
handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
((Button) findViewById(R.id.but_resend)).setVisibility(View.VISIBLE);
}
}, 20000); // produce 20 sec delay in button visibility
}
and keep in mind to hide the visibility in the.xml file by
android:visibility="invisible"