user1610719
user1610719

Reputation: 1303

Handling multiple Runnables() in Android

I'm trying to animate 4 images in succession, switching the animation when I get a new GCM message that sends a Broadcast Intent. I'll show the code for the first 2, and what is going wrong. Basically between the two commands(case 0 vs case 1), I need to be able to stop the first runnable and then start the 2nd. I try to do that by setting

isRunning = false;

but that doesn't work. I'm thinking if I kept hacking away I may get this right, but I am wondering what the correct way to do it is.

public void startAnimatedBackground(Integer num) {
    isRunning = false;
    ImageSwitcher imageSwitcher = null;
    aniIn = AnimationUtils.loadAnimation(this,
            android.R.anim.fade_in);
    aniOut = AnimationUtils.loadAnimation(this,
            android.R.anim.fade_out);

    aniIn.setDuration(500);
    aniOut.setDuration(500);
    switch (num) {
        case 0:
            imageSwitcher = (ImageSwitcher) findViewById(R.id.switcher_accept);
            break;
        case 1:
            imageSwitcher = (ImageSwitcher) findViewById(R.id.switcher_on_way);
            break;
        default:
            break;
    }
    imageSwitcher.setInAnimation(aniIn);
    imageSwitcher.setOutAnimation(aniOut);
    imageSwitcher.setFactory(this);
    imageSwitcher.setImageResource(images[0]);
    isRunning = true;
    final Handler handler = new Handler();
    final ImageSwitcher finalImageSwitcher = imageSwitcher;
    Runnable runnable = new Runnable() {

        @Override
        public void run() {
            if (isRunning) {
                System.out.println("Running.."+finalImageSwitcher+index);
                index++;
                index = index % images.length;
                finalImageSwitcher.setImageResource(images[index]);
                handler.postDelayed(this, interval);
            }
        }
    };
    handler.postDelayed(runnable, interval);

}

This is what happens at first, and it is correct. I get a blinking image.

...app:id/switcher_accept}1 ...app:id/switcher_accept}0 ...app:id/switcher_accept}1 ...app:id/switcher_accept}0 ...app:id/switcher_accept}1

After case 2 runs, this is what the running process looks like. As you can see, both are running, and none of the expected behavior is happening. What I want is the 2nd(switcher_on_way) to run just like the first was before. I was hoping my isRunning=false; code would let this happen, but it obviously isn't.

...app:id/switcher_on_way}0 ...app:id/switcher_accept}1 ...app:id/switcher_on_way}0 ...app:id/switcher_accept}1 ...app:id/switcher_on_way}0 ...app:id/switcher_accept}1

Upvotes: 0

Views: 1815

Answers (1)

T D Nguyen
T D Nguyen

Reputation: 7613

Your problem lies in this block:

Runnable runnable = new Runnable() {

    @Override
    public void run() {
        if (isRunning) {
            System.out.println("Running.."+finalImageSwitcher+index);
            ...
            handler.postDelayed(this, interval);
        }
    }
};
handler.postDelayed(runnable, interval);

You tried to create a loop and control it via isRunning variable. However, the problem is the condition is checked in the middle of the interval when isRunning is true.

1: Start _isRunning=false______Check(isRunning)________Check(isRunning)
2: ___Start _isRunning=false___isRunning=true_______isRunning=true

and you need other approach, for example: create global handler instead of local and then cancel the postDelayed when you start a new animation. Refer to: cancelling a handler.postdelayed process

or you can use wait, synchronized, and notify.

Upvotes: 1

Related Questions