重复一个任务有一段时间?
我在我的代码中有一个variables说它是“状态”。
我想根据这个variables值在应用程序中显示一些文本。 这必须在特定的时间延迟下完成。
就像是,
-
检查状态variables值
-
显示一些文字
-
等待10秒
-
检查状态variables值
-
显示一些文字
-
等待15秒
等等。 时间延迟可能会有所不同,并且一旦显示文本就会被设置。
我已经尝试Thread.sleep(time delay)
,并失败。 有没有更好的方法来完成这个任务?
你应该使用Handler
的postDelayed
函数来达到这个目的。 它将在主UI线程上以指定的延迟运行你的代码,所以你将能够更新UI控件。
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); }
对于任何感兴趣的人来说,下面是我创build的一个类,它使用inazaruk的代码创build了所需的所有东西(我称之为UIUpdater,因为我使用它来定期更新UI,但是您可以随意调用它):
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); } }
然后你可以在你的类中创build一个UIUpdater对象,像这样使用它:
... mUIUpdater = new UIUpdater(new Runnable() { @Override public void run() { // do stuff ... } }); // Start updates mUIUpdater.startUpdates(); // Stop updates mUIUpdater.stopUpdates(); ...
如果您想将其用作活动更新程序,请将onResume()方法中的开始调用以及onPause()中的stop方法调用,以便根据活动可见性启动和停止更新。
我认为新的热点是使用ScheduledThreadPoolExecutor 。 像这样:
private final ScheduledThreadPoolExecutor executor_ = new ScheduledThreadPoolExecutor(1); this.executor_.scheduleWithFixedDelay(new Runnable() { @Override public void run() { update(); } }, 0L, kPeriod, kTimeUnit);
计时器工作正常。 在这里,我使用Timer来1.5秒后search文本并更新UI。 希望有所帮助。
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);
计时器是另一种方式来做你的工作,但要保持安静,如果你正在使用用户界面,一定要添加runOnUiThread
。
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); }}); } } }
和XML是…
<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"/>
另一种使用CountDownTimer的方法
new CountDownTimer(30000, 1000) { public void onTick(long millisUntilFinished) { mTextField.setText("seconds remaining: " + millisUntilFinished / 1000); } public void onFinish() { mTextField.setText("done!"); } }.start();
安排一个倒计时,直到将来的一段时间,定期通知一段时间。 在文本字段中显示30秒倒数的示例:
详情
您可以使用处理程序发布可运行代码。 这个技巧在这里很好地概述: https : //guides.codepath.com/android/Repeating-Periodic-Tasks
尝试下面的例子它的作品!
在onCreate()方法中使用[Handler],该方法使用postDelayed()方法,该方法导致Runnable被添加到消息队列中,在给定示例中经过指定的时间量为0之后运行。 1
参考这个代码:
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //------------------ //------------------ android.os.Handler customHandler = new android.os.Handler(); customHandler.postDelayed(updateTimerThread, 0); } private Runnable updateTimerThread = new Runnable() { public void run() { //write here whaterver you want to repeat customHandler.postDelayed(this, 1000); } };
就我而言,如果其中一个条件成立,我必须执行一个进程:如果之前的进程已经完成或者已经过了5秒钟。 所以,我做了以下工作,工作得很好:
private Runnable mStatusChecker; private Handler mHandler; class { method() { mStatusChecker = new Runnable() { int times = 0; @Override public void run() { if (times < 5) { if (process1.isRead()) { executeProcess2(); } else { times++; mHandler.postDelayed(mStatusChecker, 1000); } } else { executeProcess2(); } } }; mHandler = new Handler(); startRepeatingTask(); } void startRepeatingTask() { mStatusChecker.run(); } void stopRepeatingTask() { mHandler.removeCallbacks(mStatusChecker); } }
如果读取了process1,则执行process2。 如果不是,则增加variables次数,并使处理程序在一秒钟后执行。 它保持一个循环,直到process1被读取或者times是5.当times是5时,这意味着5秒钟过去了,并且在每一秒中执行process1.isRead()的if子句。
基于以上关于ScheduledThreadPoolExecutor的post,我想出了一个适合我的需求的实用程序(想要每3秒触发一个方法):
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); } }
在Handler的帮助下以Android的方式进行操作。
声明一个不会在Activity / Fragment类中泄漏内存的内部Handler类
/** * 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) { // ... } } }
声明一个将在Activity / Fragment类中执行重复任务的runnable
private Runnable repeatativeTaskRunnable = new Runnable() { public void run() { new Handler(getMainLooper()).post(new Runnable() { @Override public void run() { //DO YOUR THINGS } };
初始化Activity / Fragment中的Handler对象(这里FlashActivity是我的活动类)
//Task Handler private Handler taskHandler = new NonLeakyHandler(FlashActivity.this);
在修复时间间隔后重复任务
taskHandler.postDelayed(repeatativeTaskRunnable,DELAY_MILLIS);
停止重复任务
taskHandler .removeCallbacks(repeatativeTaskRunnable);