jkflipflop
jkflipflop

Reputation: 5

A line of code is looping after reading from accelerometer in android

This is the only problem I keep running into in my app. n=0 by default and will be set to 1 if the gravity value from the accelerometer will be above a certain value. Once n=1 (the gravity detected is high enough) the method "action()" will be called. Since the gravity value from the accelerometer changes really fast I needed to call action() and wait a little bit before changing n back to 0 or action() will be called a few times in a row.

I tried to use sleep() after calling action and before changing n to 0 but it didn't work. I then tried to use the count down timer for 5 seconds and it just looped action(); really fast for 5 seconds before stopping. It might be my lack of understanding of the android count down timer which is weird because I used it in other parts of my code and it worked perfectly.

    if(n == 1){
        if (state == true) {
            action();
            new CountDownTimer(5000, 1000) {
                @Override
                public void onTick(long millisUntilFinished) {
                }

                public void onFinish() {
                    n = 0;
                }
            }.start();
        }
    }

I just need a way for action() to be called only once and then set n to 0 in order to be ready for another read from the accelerometer.

Thanks!

Upvotes: 0

Views: 79

Answers (2)

user2711811
user2711811

Reputation:

The @DigitalNinja answer has a better fit for your posted code - but consider this alternative:

Define a class:

public class ActionTrigger {

   private int latchTimeInMillis;
   private long lastTrigger = 0;

   public ActionTrigger(int latchTimeInMillis)
   {
      this.latchTimeInMillis = latchTimeInMillis;
   }

   /** Invoke 'action' on first trigger or after desired interval. */       
   public void trigger()
   {
      long cTime = System.currentTimeInMillis();

      if ((cTime - lastTrigger) > latchTimeInMillis)
      {
         action();
         lastTrigger = cTime;
      }
   }

}

During your code initialization create an instance:

ActionTrigger myActionTrigger = new ActionTrigger(5000);

And your OP code becomes:

// if current gravity reading exceeds threshold
if(n == 1) {
    // the associated 'action' only gets called initially or after desired interval
    myActionTrigger.trigger();
}

If you want to generalize the ActionTrigger and allow for different "action"s then you can define a callback mechanism in the constructor such as:

public interface ActionTriggerCallack
{
   public void onTrigger();
}

And add the callback as a constructor parameter

public ActionTrigger(int latchTimeInMillis, ActionTriggerCallback cb) {...}

and instead of directly calling 'action' call:

    cb.onTrigger();

and change the original initialization:

ActionTrigger myActionTrigger = new ActionTrigger(5000, 
        new ActionTriggerCallback() {
            public void onTrigger() { action(); } 
        });

Upvotes: 0

DigitalNinja
DigitalNinja

Reputation: 1098

I think I understand what you're trying to achieve and this is probably just going to be a Homer Simpson "D'oh!" moment for you...

When n=1, you want to call action(), well then action() will continue to be called as along as n=1 and state=true. Your countdown timer will keep n=1 until 5 seconds have passed, at which time it gets set to zero preventing action() from being called. Furthermore, your creating a new countdown timer over and over again, for as long as n=1 and the state=true.

What you actually want to do is immediately set n to zero and state to false. If n becomes 1 again the state will prevent action() from being called. Then after your countdown finishes set the state back to true, which will allow action to be called again. If state is being used elsewhere then you will probably need another Boolean variable to use as your control. This way the accelerometer can set n to 1 whenever it wants but you won't care until the state is true.

if(n == 1){
    if (state == true) {
        n=0;
        state=false;
        action();
        new CountDownTimer(5000, 1000) {
            @Override
            public void onTick(long millisUntilFinished) {
            }

            public void onFinish() {
               state=true;
            }
        }.start();
    }
}

Upvotes: 1

Related Questions