4

I need to stop a Runnable from running when an image is clicked in my Android app. I'm running this Runnable repeatedly using ImageView.postDelayed():

r = new Runnable() {
    public void run() {
        imgview.setImageResource(imageArray[i]);
        i++;
        if (i >= imageArray.length) {
            i = 0;
        }
        imgview.postDelayed(r, 20); // set to go off again in 3 seconds.
        // imgview.setOnClickListener(this);
    }

};
imgview.postDelayed(r, 20); // set first time for 3 seconds

But under certain conditions I want to stop it from running, after it's already started. Here's the full code for my activity:

    public class MainActivity extends Activity  {

        int i = 0;

        ImageView imgview, imgview2;
        Handler handler = new Handler();
        Runnable r;
        MediaPlayer mMediaPlayer;
        int[] imageArray = { R.drawable.f1, R.drawable.f2, R.drawable.f3,
                R.drawable.f4, R.drawable.f5, R.drawable.f6, R.drawable.f7,
                R.drawable.f8, R.drawable.f9, R.drawable.f10, R.drawable.f11,
                R.drawable.f12, R.drawable.f13, R.drawable.f14, R.drawable.f15,
                R.drawable.f16, R.drawable.f17, R.drawable.f18, R.drawable.f19,
                R.drawable.f20, R.drawable.f21, R.drawable.f22, R.drawable.f23,
                R.drawable.f24, R.drawable.f25, R.drawable.f26, R.drawable.f27,
                R.drawable.f28 };

        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.tapp_activity);

            imgview = (ImageView) findViewById(R.id.imageView1);

            mMediaPlayer = new MediaPlayer();
            mMediaPlayer = MediaPlayer.create(MainActivity.this, R.raw.water);
            mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);



            imgview2 = (ImageView) findViewById(R.id.imageView2);

            imgview2.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    // TODO Auto-generated method stub




                    if(i==0)
                    {
                    mMediaPlayer.setLooping(true);
                    mMediaPlayer.start();
                    i=1;
                    r = new Runnable() {
                        public void run() {
                            imgview.setImageResource(imageArray[i]);
                            i++;
                            if (i >= imageArray.length) {
                                i = 0;
                            }
                            imgview.postDelayed(r, 20); // set to go off again in 3 seconds.
                            // imgview.setOnClickListener(this);
                        }

                    };
                    imgview.postDelayed(r, 20); // set first time for 3 seconds
                    }
                    else
                    {
                    i=0;

                    mMediaPlayer.stop();
                    imgview.setBackgroundResource(R.drawable.tapstill);
                    }



                }
            });


        }


        @Override
        protected void onDestroy() {
            // TODO Auto-generated method stub
            super.onDestroy();
            mMediaPlayer.stop();

        }



    }

What can I change in my code so that my Runnable stops running in the else condition of my onClick() method?

Dan Getz
  • 8,774
  • 6
  • 30
  • 64
Amit Prajapati
  • 13,525
  • 8
  • 62
  • 84
  • 3
    Possible duplicate of [Android: How do I stop Runnable?](http://stackoverflow.com/questions/9458097/android-how-do-i-stop-runnable) – patryk.beza May 12 '16 at 09:53
  • @patryk.beza that's not a duplicate of this question. See the accepted answer. I'll try to edit the question so it's clearer what's being asked. – Dan Getz May 12 '16 at 15:44

3 Answers3

4

You might try removing the callback.

imgview.removeCallbacks(r);

In order for this to work, though. you'd have to ensure that r is the same Runnable as the one you posted. You could do this by creating it once, possibly in onCreate. Since the Runnable doesn't have any dependency on the ClickListener anyway, this shouldn't be a problem.

You might also need to do some synchronization in order to prevent the case where you're removing a currently running callback, though, now that i think about it. The volatile boolean running idea is probably less complex overall.

cHao
  • 84,970
  • 20
  • 145
  • 172
2

You can control your run() method with a boolean flag:

boolean running = true;
 ...

r = new Runnable()
{
         public void run() 
         {
             if(running)
             {
                 imgview.setImageResource(imageArray[i]);
                 i++;
                 if (i >= imageArray.length) {
                     i = 0;
                 }
                 imgview.postDelayed(r, 20); 
             }
         };
}

If you set running = false later on, your thread will be idle and that's what you want.

Juvanis
  • 25,802
  • 5
  • 69
  • 87
-3

You can do it by

         Thread.stop();
Nirav Tukadiya
  • 3,367
  • 1
  • 18
  • 36
  • 2
    No, you can't. See: [Java documentation on Thread](http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#stop%28%29) – nkr Dec 05 '12 at 13:07
  • 1
    Besides the fact that [`Thread.stop()` is deprecated](http://docs.oracle.com/javase/7/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html), where's the Thread to stop? – cHao Dec 05 '12 at 13:09
  • (1) `Thread` is the class. You can't just `Thread.stop()`; `stop` is not static, and thus requires an instance. One you don't have a reference to. You could presumably say `Thread.currentThread()` within the Runnable to get such a reference, but (2) the thread being stopped is not the current thread; otherwise, you could just return. – cHao Dec 05 '12 at 17:36