2

I'm new to Android and Java programming. I created an app for a Coursera class. It has two animations that occur repeatedly. I want them to animate like a drum beat - 1,2,1,2,1,2,1,2,1,2.

I wrote two recursive methods that run until the user clicks a Reset button. I tried adding a wait in between the method calls so the second would kick off right after the first one.

This is the part of my code that has the wait.

mHandler = new Handler(); // .os package class when importing
        mLeftfoot = findViewById(R.id.leftfoot);
        mRightfoot = findViewById(R.id.rightfoot);  
        mFootAnim = AnimationUtils.loadAnimation(this, R.anim.foot); //this looks to the foot.xml file for the animations
        leftstepRecursive();
        try {
            wait(600);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        rightstepRecursive();

This part of my code shows the recursive methods, which could probably be written better I know. A lot of DRY...

private void leftstepRecursive() {
        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                mLeftfoot.startAnimation(mFootAnim);
                if (!pleaseStop)
                    leftstepRecursive();
            }
        }, mIntervalleft);}

    private void rightstepRecursive() {
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    mRightfoot.startAnimation(mFootAnim);
                    if (!pleaseStop)
                        rightstepRecursive();
                }
            }, mIntervalright);

Any better ideas to implement this left, right, left, right, left, right, left, right, left, right, idea?

Or, what I can do to correct the wait?

I also tried this:

private void rightstepRecursive() {
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    Object testobj = mRightfoot.startAnimation(mFootAnim);
                    synchronized (testobj) {
                        testobj.wait(600);
                    }
                    if (!pleaseStop)
                        rightstepRecursive();
                }
            }, mIntervalright);

@LuigiMendoza. I tried thread(sleep). No errors, but both animations move simultaneously not sure why...

private void rightstepRecursive() {
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    mRightfoot.startAnimation(mFootAnim);
                    if (!pleaseStop)
                        rightstepRecursive();
                }
            }, mIntervalright);

            try
            {
                Thread.sleep(500);
            } catch (InterruptedException e)
            {
                e.printStackTrace();
            }
}

I also get this message repeating in Logcat.

02-11 12:15:32.261: I/Choreographer(30480): Skipped 302 frames!  The application may be doing too much work on its main thread.
Dreamwalker
  • 3,032
  • 4
  • 30
  • 60
StacyM
  • 1,036
  • 5
  • 23
  • 41
  • I'm not sure if you should use `wait` or `Thread.sleep` in this case. – Luiggi Mendoza Feb 11 '14 at 19:57
  • See my Thread.sleep above...it doesn't work. Both animations happen simultaneously. I want the mRightfoot to kick off 500 ms after mLeftfoot. – StacyM Feb 11 '14 at 20:14
  • Please don't prefix your question titles with `Android`, the tag at the bottom is more than enough. You don't want to use `Thread.sleep()` or `wait`(which requires synchronization see http://stackoverflow.com/questions/1036754/difference-between-wait-and-sleep) . There's no need to actually sleep to start the right method, just use the same `Handler` approach to post a delayed message(after 600 ms) right after the line where you call the left animation, in that delayed `Runnable` simply call the right method that you want to start after 600ms. – user Feb 11 '14 at 20:18
  • Luksprog. thanks! Ok, no more Android prefixes. Could you post your code example. You should get credit for your response. – StacyM Feb 11 '14 at 20:20
  • Oh I mean post any answer, not a comment. You should get credit rather than u/Submersed. His/her answer is helpful but doesn't directly fix my current issue with my code that was posted. – StacyM Feb 11 '14 at 20:35
  • Luksprog, I thought about your answer and if you put mLeftfoot.startAnimation(mFootAnim); and mRightfoot.startAnimation(mFootAnim); in the same Handler/Runnable they will animate at the same time. They would both have the same delay of 600 ms, same as my mInterval. – StacyM Feb 11 '14 at 20:48
  • Have a look at https://gist.github.com/luksprog/8943484 I didn't posted an answer because I don't know your entire setup and there's no point in guessing. – user Feb 11 '14 at 20:49
  • I just tried your example. The left foot animates once, the right foot alternates correctly, but the left foot never animates again. The right foot animates and repeats correctly. – StacyM Feb 11 '14 at 21:01
  • Fixed it. I had to change the do a one time delay of 500 ms in your one time postDelayed and then double the global delay of 1000 (doubling the left foot, 500 ms). You should have posted an answer. Your answer was the most helpful. – StacyM Feb 12 '14 at 00:48

1 Answers1

3

You should really utilize the Animations framework and some of the classes it provides such as AnimationListeners and AnimatorSets. The Animations framework provides a lot of functionality that would really simplify what you are trying to do i.e. repeating animations, adding delays, timing animations, etc.

Here's a really bare bones example to give the basic idea:

AnimatorSet animations;

//Play the animation
private void playAnimation(){       
    //If they haven't stopped the animation, loop it.
        ObjectAnimator anim1 = ObjectAnimator.ofFloat(target, propertyName, values);
        ObjectAnimator anim2 = ObjectAnimator.ofFloat(target, propertyName, values);
        animations = new AnimatorSet();
        animations.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                playAnimation();
            }
        });
        animations.play(anim1).before(anim2);
            animations.start();

}

//Called when cancel is selected
private void stopAnimation(){
    animations.end();
}
Submersed
  • 8,810
  • 2
  • 30
  • 38
  • Thanks, at first glance the Handler/Recursive method code seems easier to understand. In my code the actual animation is in a foot.xml and it's easy to change animation (sliding, opaqueness) there. Where do you address the actual animation in your code? Target, propertyName, values? – StacyM Feb 11 '14 at 20:28
  • Target is the object, so your view, propertyName is what you are animating...so, this could be "x" or "y", etc, and values is your start and end, or just end value (if you specify only one value, it treats it as the end value). It's all in the documentation. – Submersed Feb 11 '14 at 20:44
  • Also, note that you can create objectAnimators in xml as well. – Submersed Feb 11 '14 at 20:59
  • Not sure if you're still checking this, but I fixed my other way using recursive methods. In your example, where would I control the interval /speed between anim1 and anim2? – StacyM Feb 12 '14 at 00:53
  • By setting a custom/different Interpolator, see setInterpolator – Submersed Feb 12 '14 at 01:05