1

I made "heart beat effect button"(Continuous blinking) using ObjectAnimator, And it works fine.

There is 4 buttons, named btn1RT, btn2LT, btn3LB and btn4RB. If one of the button starts blinking, other buttons will be disappeared.

Question: I refactored this code, and it does not working anymore. I can't stop buttons from blinking, so all of my buttons are blinking. I want to know why these buttons cannot be stopped.

I think passing ObjectAnimator as a parameter is problem, but there is no clue.

Any help will be appreciated.

Before:

private void start1HeartBeat() {
        oa1 = ObjectAnimator.ofFloat(btn1RT, "alpha", 1, 0);
        oa1.setDuration(HEARTBEAT_RUN_DURATION);
        oa1.setRepeatCount(ValueAnimator.INFINITE);
        oa1.setRepeatMode(ValueAnimator.REVERSE);
        oa1.start();

        if (oa2.isRunning()) {
            oa2.end();
            oa2 = ObjectAnimator.ofFloat(btn2LT, "alpha", 0.5f, 0);
            oa2.setDuration(HEARTBEAT_STOP_DURATION);
            oa2.setRepeatCount(0);
            oa2.setRepeatMode(ValueAnimator.RESTART);
            oa2.start();
        }

        if (oa3.isRunning()) {
            oa3.end();
            oa3 = ObjectAnimator.ofFloat(btn3LB, "alpha", 0.5f, 0);
            oa3.setDuration(HEARTBEAT_STOP_DURATION);
            oa3.setRepeatCount(0);
            oa3.setRepeatMode(ValueAnimator.RESTART);
            oa3.start();
        }

        if (oa4.isRunning()) {
            oa4.end();
            oa4 = ObjectAnimator.ofFloat(btn4RB, "alpha", 0.5f, 0);
            oa4.setDuration(HEARTBEAT_STOP_DURATION);
            oa4.setRepeatCount(0);
            oa4.setRepeatMode(ValueAnimator.RESTART);
            oa4.start();
        }
    }
}

After refactored: this is not working.

private void start1HeartBeat() {
    startHeartBeat(oa1, btn1RT);
    stopHeartBeat(oa2, btn2LT);
    stopHeartBeat(oa3, btn3LB);
    stopHeartBeat(oa4, btn4RB);
}

private synchronized void startHeartBeat(ObjectAnimator oa, Object btn) {
        oa = ObjectAnimator.ofFloat(btn, "alpha", 1, 0);
        oa.setDuration(HEARTBEAT_RUN_DURATION);
        oa.setRepeatCount(ValueAnimator.INFINITE);
        oa.setRepeatMode(ValueAnimator.REVERSE);
        oa.start();
    }

private synchronized void stopHeartBeat(ObjectAnimator oa, Object btn) {
    if (oa.isRunning()) {
        oa.end();
        oa = ObjectAnimator.ofFloat(btn, "alpha", 0.5f, 0);
        oa.setDuration(HEARTBEAT_STOP_DURATION);
        oa.setRepeatCount(0);
        oa.setRepeatMode(ValueAnimator.RESTART);
        oa.start();
    }
}
Stanley Ko
  • 3,383
  • 3
  • 34
  • 60

1 Answers1

2

To understand the problem we should be clear about the difference between pass-by-value and pass-by-reference. For the case of Java, this post better clarifies the concept.

In short, in Java the reference itself is pass-by-value. As we know in pass-by-value the change inside a method is not reflected outside. Hence changing the passed reference inside a method is not reflected outside.

With this knowledge, one of the way to correctly refactor the code is as follows

private void start1HeartBeat() {
    oa1 = startHeartBeat(oa1, btn1RT);
    oa2 = stopHeartBeat(oa2, btn2LT);
    oa3 = stopHeartBeat(oa3, btn3LB);
    oa4 = stopHeartBeat(oa4, btn4RB);
}

private synchronized ObjectAnimator startHeartBeat(ObjectAnimator oa, Object btn) {
    oa = ObjectAnimator.ofFloat(btn, "alpha", 1, 0);
    oa.setDuration(HEARTBEAT_RUN_DURATION);
    oa.setRepeatCount(ValueAnimator.INFINITE);
    oa.setRepeatMode(ValueAnimator.REVERSE);
    oa.start();
    return oa;
}

private synchronized ObjectAnimator stopHeartBeat(ObjectAnimator oa, Object btn) {
    if (oa.isRunning()) {
        oa.end();
        oa = ObjectAnimator.ofFloat(btn, "alpha", 0.5f, 0);
        oa.setDuration(HEARTBEAT_STOP_DURATION);
        oa.setRepeatCount(0);
        oa.setRepeatMode(ValueAnimator.RESTART);
        oa.start();
    }
    return oa;
}

I just mentioned one possible way to refactor. Since the core problem is clarified, you do refactor in an appropriate way.

Community
  • 1
  • 1
Durgadass S
  • 1,098
  • 6
  • 13
  • I am sorry that I didn't mention ObjectAnimator oa1, oa2, oa3, oa4 is global variables. And unfortunately, this code doesn't works. – Stanley Ko Nov 02 '15 at 02:04
  • @StanleyKou I know that oa1, etc are member variables. The reference for the instance `oa` inside both refactored methods are not available outside the methods. Of course you are passing the reference of member variables, but the reference itself is passed-by-value, that's how java works. The scope of new instance you are creating inside the method is local. So to stop the animation in future you have to somehow hold the reference in a/the member variable. I mentioned one way. – Durgadass S Nov 02 '15 at 16:46
  • @StanleyKou Up to my knowledge, if the code you mentioned before refactoring works, then the code I gave should also work. – Durgadass S Nov 02 '15 at 16:55
  • That is a strange point. The code you sugessted was exactly same as mine. And, up to my knowledge, all of these code must be work. But it wasn't. Now I'm analyzing another point that I didn't wrote here. Anyway, thank you for your answer. – Stanley Ko Nov 03 '15 at 09:39
  • Oh, I was wrong. I got your point. I am trying to run my global ObjectAnimator, and get new ObjectAnimator, and forget about the new ObjectAnimator! – Stanley Ko Nov 03 '15 at 10:39