Repeat a task with a time delay?

后端 未结 12 1412
小蘑菇
小蘑菇 2020-11-22 02:14

I have a variable in my code say it is \"status\".

I want to display some text in the application depending on this variable value. This has to be done with a speci

相关标签:
12条回答
  • 2020-11-22 02:41

    Based on the above post concerning the ScheduledThreadPoolExecutor, I came up with a utility that suited my needs (wanted to fire a method every 3 seconds):

    class MyActivity {
        private ScheduledThreadPoolExecutor mDialogDaemon;
    
        private void initDebugButtons() {
            Button btnSpawnDialogs = (Button)findViewById(R.id.btn_spawn_dialogs);
            btnSpawnDialogs.setVisibility(View.VISIBLE);
            btnSpawnDialogs.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View view) {
                    spawnDialogs();
                }
            });
        }
    
        private void spawnDialogs() {
            if (mDialogDaemon != null) {
                mDialogDaemon.shutdown();
                mDialogDaemon = null;
            }
            mDialogDaemon = new ScheduledThreadPoolExecutor(1);
            // This process will execute immediately, then execute every 3 seconds.
            mDialogDaemon.scheduleAtFixedRate(new Runnable() {
                @Override
                public void run() {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            // Do something worthwhile
                        }
                    });
                }
            }, 0L, 3000L, TimeUnit.MILLISECONDS);
        }
    }
    
    0 讨论(0)
  • 2020-11-22 02:43

    To anyone interested, here's a class I created using inazaruk's code that creates everything needed (I called it UIUpdater because I use it to periodically update the UI, but you can call it anything you like):

    import android.os.Handler;
    /**
     * A class used to perform periodical updates,
     * specified inside a runnable object. An update interval
     * may be specified (otherwise, the class will perform the 
     * update every 2 seconds).
     * 
     * @author Carlos Simões
     */
    public class UIUpdater {
            // Create a Handler that uses the Main Looper to run in
            private Handler mHandler = new Handler(Looper.getMainLooper());
    
            private Runnable mStatusChecker;
            private int UPDATE_INTERVAL = 2000;
    
            /**
             * Creates an UIUpdater object, that can be used to
             * perform UIUpdates on a specified time interval.
             * 
             * @param uiUpdater A runnable containing the update routine.
             */
            public UIUpdater(final Runnable uiUpdater) {
                mStatusChecker = new Runnable() {
                    @Override
                    public void run() {
                        // Run the passed runnable
                        uiUpdater.run();
                        // Re-run it after the update interval
                        mHandler.postDelayed(this, UPDATE_INTERVAL);
                    }
                };
            }
    
            /**
             * The same as the default constructor, but specifying the
             * intended update interval.
             * 
             * @param uiUpdater A runnable containing the update routine.
             * @param interval  The interval over which the routine
             *                  should run (milliseconds).
             */
            public UIUpdater(Runnable uiUpdater, int interval){
                UPDATE_INTERVAL = interval;
                this(uiUpdater);
            }
    
            /**
             * Starts the periodical update routine (mStatusChecker 
             * adds the callback to the handler).
             */
            public synchronized void startUpdates(){
                mStatusChecker.run();
            }
    
            /**
             * Stops the periodical update routine from running,
             * by removing the callback.
             */
            public synchronized void stopUpdates(){
                mHandler.removeCallbacks(mStatusChecker);
            }
    }
    

    You can then create a UIUpdater object inside your class and use it like so:

    ...
    mUIUpdater = new UIUpdater(new Runnable() {
             @Override 
             public void run() {
                // do stuff ...
             }
        });
    
    // Start updates
    mUIUpdater.startUpdates();
    
    // Stop updates
    mUIUpdater.stopUpdates();
    ...
    

    If you want to use this as an activity updater, put the start call inside the onResume() method and the stop call inside the onPause(), so the updates start and stop according to the activity visibility.

    0 讨论(0)
  • 2020-11-22 02:45

    Timer works fine. Here, I use Timer to search text after 1.5s and update UI. Hope that helps.

    private Timer _timer = new Timer();
    
    _timer.schedule(new TimerTask() {
        @Override
        public void run() {
            // use runOnUiThread(Runnable action)
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    search();
                }
            });
        }
    }, timeInterval);
    
    0 讨论(0)
  • 2020-11-22 02:53

    You should use Handler's postDelayed function for this purpose. It will run your code with specified delay on the main UI thread, so you will be able to update UI controls.

    private int mInterval = 5000; // 5 seconds by default, can be changed later
    private Handler mHandler;
    
    @Override
    protected void onCreate(Bundle bundle) {
    
        // your code here
    
        mHandler = new Handler();
        startRepeatingTask();
    }
    
    @Override
    public void onDestroy() {
        super.onDestroy();
        stopRepeatingTask();
    }
    
    Runnable mStatusChecker = new Runnable() {
        @Override 
        public void run() {
              try {
                   updateStatus(); //this function can change value of mInterval.
              } finally {
                   // 100% guarantee that this always happens, even if
                   // your update method throws an exception
                   mHandler.postDelayed(mStatusChecker, mInterval);
              }
        }
    };
    
    void startRepeatingTask() {
        mStatusChecker.run(); 
    }
    
    void stopRepeatingTask() {
        mHandler.removeCallbacks(mStatusChecker);
    }
    
    0 讨论(0)
  • 2020-11-22 02:53

    Timer is another way to do your work but be quiet sure to add runOnUiThread if you are working with UI.

        import java.text.SimpleDateFormat;
    import java.util.Calendar;
    import java.util.Timer;
    import java.util.TimerTask;
    
    import android.os.Bundle;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    import android.widget.CheckBox;
    import android.widget.TextView;
    import android.app.Activity;
    
    public class MainActivity extends Activity {
    
     CheckBox optSingleShot;
     Button btnStart, btnCancel;
     TextView textCounter;
    
     Timer timer;
     MyTimerTask myTimerTask;
    
     @Override
     protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      optSingleShot = (CheckBox)findViewById(R.id.singleshot);
      btnStart = (Button)findViewById(R.id.start);
      btnCancel = (Button)findViewById(R.id.cancel);
      textCounter = (TextView)findViewById(R.id.counter);
    
      btnStart.setOnClickListener(new OnClickListener(){
    
       @Override
       public void onClick(View arg0) {
    
        if(timer != null){
         timer.cancel();
        }
    
        //re-schedule timer here
        //otherwise, IllegalStateException of
        //"TimerTask is scheduled already" 
        //will be thrown
        timer = new Timer();
        myTimerTask = new MyTimerTask();
    
        if(optSingleShot.isChecked()){
         //singleshot delay 1000 ms
         timer.schedule(myTimerTask, 1000);
        }else{
         //delay 1000ms, repeat in 5000ms
         timer.schedule(myTimerTask, 1000, 5000);
        }
       }});
    
      btnCancel.setOnClickListener(new OnClickListener(){
    
       @Override
       public void onClick(View v) {
        if (timer!=null){
         timer.cancel();
         timer = null;
        }
       }
      });
    
     }
    
     class MyTimerTask extends TimerTask {
    
      @Override
      public void run() {
       Calendar calendar = Calendar.getInstance();
       SimpleDateFormat simpleDateFormat = 
         new SimpleDateFormat("dd:MMMM:yyyy HH:mm:ss a");
       final String strDate = simpleDateFormat.format(calendar.getTime());
    
       runOnUiThread(new Runnable(){
    
        @Override
        public void run() {
         textCounter.setText(strDate);
        }});
      }
    
     }
    
    }
    

    and xml is...

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context=".MainActivity" >
    
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />
    <CheckBox 
        android:id="@+id/singleshot"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Single Shot"/>
    

    Another Way to use CountDownTimer

    new CountDownTimer(30000, 1000) {
    
         public void onTick(long millisUntilFinished) {
             mTextField.setText("seconds remaining: " + millisUntilFinished / 1000);
         }
    
         public void onFinish() {
             mTextField.setText("done!");
         }
      }.start();
    

    Schedule a countdown until a time in the future, with regular notifications on intervals along the way. Example of showing a 30 second countdown in a text field:

    For Details

    0 讨论(0)
  • 2020-11-22 02:55

    There are 3 ways to do it:

    Use ScheduledThreadPoolExecutor

    A bit of overkill since you don't need a pool of Thread

       //----------------------SCHEDULER-------------------------
        private final ScheduledThreadPoolExecutor executor_ =
                new ScheduledThreadPoolExecutor(1);
         ScheduledFuture<?> schedulerFuture;
       public void  startScheduler() {
           schedulerFuture=  executor_.scheduleWithFixedDelay(new Runnable() {
                @Override
                public void run() {
                    //DO YOUR THINGS
                    pageIndexSwitcher.setVisibility(View.GONE);
                }
            }, 0L, 5*MILLI_SEC,  TimeUnit.MILLISECONDS);
        }
    
    
        public void  stopScheduler() {
            pageIndexSwitcher.setVisibility(View.VISIBLE);
            schedulerFuture.cancel(false);
            startScheduler();
        }
    

    Use Timer Task

    Old Android Style

        //----------------------TIMER  TASK-------------------------
    
        private Timer carousalTimer;
        private void startTimer() {
            carousalTimer = new Timer(); // At this line a new Thread will be created
            carousalTimer.scheduleAtFixedRate(new TimerTask() {
                @Override
                public void run() {
                    //DO YOUR THINGS
                    pageIndexSwitcher.setVisibility(INVISIBLE);
                }
            }, 0, 5 * MILLI_SEC); // delay
        }
    
        void stopTimer() {
            carousalTimer.cancel();
        }
    

    Use Handler and Runnable

    Modern Android Style

        //----------------------HANDLER-------------------------
    
        private Handler taskHandler = new android.os.Handler();
    
        private Runnable repeatativeTaskRunnable = new Runnable() {
            public void run() {
                //DO YOUR THINGS
            }
        };
    
       void startHandler() {
            taskHandler.postDelayed(repeatativeTaskRunnable, 5 * MILLI_SEC);
        }
    
        void stopHandler() {
            taskHandler.removeCallbacks(repeatativeTaskRunnable);
        }
    

    Non-Leaky Handler with Activity / Context

    Declare an inner Handler class which does not leak Memory in your Activity/Fragment class

    /**
         * Instances of static inner classes do not hold an implicit
         * reference to their outer class.
         */
        private static class NonLeakyHandler extends Handler {
            private final WeakReference<FlashActivity> mActivity;
    
            public NonLeakyHandler(FlashActivity activity) {
                mActivity = new WeakReference<FlashActivity>(activity);
            }
    
            @Override
            public void handleMessage(Message msg) {
                FlashActivity activity = mActivity.get();
                if (activity != null) {
                    // ...
                }
            }
        }
    

    Declare a runnable which will perform your repetitive task in your Activity/Fragment class

       private Runnable repeatativeTaskRunnable = new Runnable() {
            public void run() {
                new Handler(getMainLooper()).post(new Runnable() {
                    @Override
                    public void run() {
    
             //DO YOUR THINGS
            }
        };
    

    Initialize Handler object in your Activity/Fragment (here FlashActivity is my activity class)

    //Task Handler
    private Handler taskHandler = new NonLeakyHandler(FlashActivity.this);
    

    To repeat a task after fix time interval

    taskHandler.postDelayed(repeatativeTaskRunnable , DELAY_MILLIS);

    To stop the repetition of task

    taskHandler .removeCallbacks(repeatativeTaskRunnable );

    UPDATE: In Kotlin:

        //update interval for widget
        override val UPDATE_INTERVAL = 1000L
    
        //Handler to repeat update
        private val updateWidgetHandler = Handler()
    
        //runnable to update widget
        private var updateWidgetRunnable: Runnable = Runnable {
            run {
                //Update UI
                updateWidget()
                // Re-run it after the update interval
                updateWidgetHandler.postDelayed(updateWidgetRunnable, UPDATE_INTERVAL)
            }
    
        }
    
     // SATART updating in foreground
     override fun onResume() {
            super.onResume()
            updateWidgetHandler.postDelayed(updateWidgetRunnable, UPDATE_INTERVAL)
        }
    
    
        // REMOVE callback if app in background
        override fun onPause() {
            super.onPause()
            updateWidgetHandler.removeCallbacks(updateWidgetRunnable);
        }
    
    0 讨论(0)
提交回复
热议问题