0

I am developing an Android application and I want to call a function every 40ms. To do so, I implemented a Handler and a Runnable. I chose this two objects thanks to the post How to run a method every X seconds. But I am not sure this is the right way to perform what I am doing :

In my application, I am playing a video, I want to "launch" the Handler when starting the video, "put it on hold" when pausing the video, starting it again when resuming the video and so on.

So far, I am using mHandler.removeCallbacks(mRunnable); to detain it. But to start it or resume it, I don't know if I should use mHandler.post(mRunnable); mHandler.postDelay(mRunnable, DELAY) or mRunnable.run();. I succeed making them all work but the behaviour is never as expected...

Here is the code I use to set up the Handler...

public void setUpdatePositionHandler() {
    mHandler = new Handler();
    mRunnable = new Runnable() {
        @Override
        public void run() {
            if (mVideoView.getCurrentPosition() > mVideoView.getDuration()) {
                if (mVideoView.getCurrentPosition() > 1000) {
                    mVideoView.seekTo(1); // go back to beginning
                    mVideoView.pause();
                    mPlayButton.setVisibility(View.VISIBLE);
                    mStampIndex = 0;
                    mLastPosition = 0;
                    Log.i(TAG, "removeCallbacks() from runnable");
                    mHandler.removeCallbacks(this);
                } else {
                    //mHandler.postDelayed(this, DELAY);
                }
            } else {
                if (!mStamps.isEmpty()) {
                    onPositionUpdate(mStamps);
                }
                mHandler.postDelayed(this, DELAY);
            }
        }
    };

Note that I don't feel really sure of what I implemented so far, and that any ressources that would help me understand better would be welcome :) (I already read the documentations of the 2 classes and read several documents or posts on the subjects, but I think I am missing something.)

Thank you for your help

Phantômaxx
  • 37,901
  • 21
  • 84
  • 115
Juliette Marquis
  • 159
  • 1
  • 1
  • 13
  • Can you explain why the behaviour is not what you are expecting? – Ivan Oct 24 '18 at 08:18
  • you likely won't be able to run your code with such precision in time. – Vladyslav Matviienko Oct 24 '18 at 08:24
  • @Ivan In one case, the runnable is running from the beginning of the video but doesn't stop when I pause the video. And in another case, it doesn't run on video launch but behave as expected when I pause and resume and pause again the video... – Juliette Marquis Oct 24 '18 at 08:24
  • Handler.postDelayed will post a runnable to be run x miliseconds after it is issued. Handler.post will post a runnable to be run after all outstanding tasks on the main thread, from the point of post being called, are completed. – Thomas Cook Oct 24 '18 at 08:26
  • You could use RX (if you don't mind bringing it as a dependancy), it let's you create really fluent timed loop. – Thomas Cook Oct 24 '18 at 08:27
  • @ThomasCook Thank you for the details about the two functions. Afte reading the documentation, I thought Handler.post would post a runnable to be run when post() was called. For using RX, I will check it out, but I must say, I would really like to understand how Handlers and Runnables work together ahahha – Juliette Marquis Oct 24 '18 at 08:41
  • Yea that is fair, always always always read the documentation. Also, you can download the source and look at it in your IDE - the ultimate source of truth (no pun intended) – Thomas Cook Oct 24 '18 at 08:56

1 Answers1

0

Is it the correct way ? if it will not produce any problem and it meets your requirements then yes but your question should be is it the best practice? i prefer to write it like the following

public void setUpdatePositionHandler() {
    mHandler = new Handler();
    mRunnable = new Runnable() {
        @Override
        public void run() {
            if (mVideoView.getCurrentPosition() > mVideoView.getDuration()) {
                if (mVideoView.getCurrentPosition() > 1000) {
                    mVideoView.seekTo(1); // go back to beginning
                    mVideoView.pause();
                    mPlayButton.setVisibility(View.VISIBLE);
                    mStampIndex = 0;
                    mLastPosition = 0;
                    Log.i(TAG, "removeCallbacks() from runnable");
                    mHandler.removeCallbacks(this);
                } else {
                    //mHandler.postDelayed(this, DELAY);
                }
            } else {
                if (!mStamps.isEmpty()) {
                    onPositionUpdate(mStamps);
                }
            }
        }
         mHandler.postDelayed(mRunnable, DELAY);
    };

be noted the above code will work only once expect if you make CountDownTimer or you can use Thread.sleep() with a normal loop and AsyncTask in order to not block your code because if so the application will not be responding and then your app will be crached

Basil Battikhi
  • 2,638
  • 1
  • 18
  • 34
  • Thanks for your answer, and you're right, I'd like to know if it is the best practice. I am not sure I understood the last paragraph though :/ – Juliette Marquis Oct 24 '18 at 08:31
  • as you mentioned you need to run the code every 40 seconds i told you this code will run one time after 40 second and then the task will be end – Basil Battikhi Oct 24 '18 at 08:54
  • Doesn't the `mHandler.postDelayed(mRunnable, DELAY);` line inside the run() function make it run severak times ? Because on the tests I did, it does run several times every 40 ms until I removeCallbacks() – Juliette Marquis Oct 24 '18 at 08:58
  • No postdelay will delay the code execution for a specific time thats why i told you to use Thread.sleep or countdown timer instead – Basil Battikhi Oct 24 '18 at 09:01
  • Thank you for your answer, I checked it out and finally found the right configuration using postDelayed() :) – Juliette Marquis Oct 25 '18 at 12:41