如何在Android中设置计时器


Answers:


143

通过java.util.Timerjava.util.TimerTask使用计时器的标准Java方法在Android 可以正常工作,但是您应该知道此方法会创建一个新线程。

您可以考虑使用非常方便的Handler类(android.os.Handler)并通过sendMessageAtTime(android.os.Message, long)或将消息发送到处理程序sendMessageDelayed(android.os.Message, long)。收到消息后,您可以运行所需的任务。第二种选择是创建一个Runnable对象,并通过Handler的函数postAtTime(java.lang.Runnable, long)或调度它postDelayed(java.lang.Runnable, long)


10
这是在android中做事的错误方式。在android中,您想使用Alarm Manager(developer.android.com/reference/android/app/AlarmManager.html)在将来运行任务。
Kurtis Nusbaum

9
@Kurtis Nusbaum问题没有说任务将来有多远。
Christopher Perry

67
@KurtisNusbaum不一定是正确的,它取决于上下文。AlarmManager上的文档说:“注意:Alarm Manager适用于您希望在特定时间运行应用程序代码的情况,即使您的应用程序当前未运行。对于正常的计时操作(滴答声,超时等)使用Handler更容易,效率也更高。”
Christopher Perry

5
@Scienceprodigy啊,我明白了。很公平。
Kurtis Nusbaum

10
仅当应用程序获取了唤醒锁后,使用Handler调度任务的方法才是可靠的,因此,您可以确保电话不会进入睡眠状态。如果电话确实进入了睡眠状态,则sendMessageDelayed和sendMessageAtTime将不起作用。因此,在那种情况下,AlarmManager将是可靠的选择。
crazyaboutliv 2012年

159

是的,可以使用 java的timer ,但是由于这个问题要求更好的方法(针对移动设备)。在这里解释。


为了StackOverflow:

由于Timer创建了新线程,因此它可能被认为很繁重,

如果您需要获得的只是在活动运行时回调,则可以将Handler

可运行的

private final int interval = 1000; // 1 Second
private Handler handler = new Handler();
private Runnable runnable = new Runnable(){
    public void run() {
        Toast.makeText(MyActivity.this, "C'Mom no hands!", Toast.LENGTH_SHORT).show();
    }
};
...
handler.postAtTime(runnable, System.currentTimeMillis()+interval);
handler.postDelayed(runnable, interval);

讯息

private final int EVENT1 = 1; 
private Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {         
        case Event1:
            Toast.makeText(MyActivity.this, "Event 1", Toast.LENGTH_SHORT).show();
            break;

        default:
            Toast.makeText(MyActivity.this, "Unhandled", Toast.LENGTH_SHORT).show();
            break;
        }
    }
};

...

Message msg = handler.obtainMessage(EVENT1);
handler.sendMessageAtTime(msg, System.currentTimeMillis()+interval);
handler.sendMessageDelayed(msg, interval);

附带说明一下,如果要从另一个线程在UI线程中运行一段代码,则可以使用此方法。

如果即使您的活动尚未运行,也需要回电,则可以使用AlarmManager


1
哦,是的,我正是在谷歌上搜索这个答案。请投票支持有用的链接。
ulidtko 2011年

1
更新了链接,谈论谷歌在维护链接方面遇到麻烦。
塞缪尔

1
2007年的这篇文章-并不是说它是错误的,但是如果这篇移动文章的历史超过3年,我总是对此感到怀疑。事情变化很快。
StackOverflowed 2012年

1
如果您可以在答案中引用链接的要点,则它更像StackOverflow。
n611x007 2013年

1
@naxa,我花了两美分使此响应更像StackOverflow。
塞缪尔

131

如我所见,java.util.Timer是实现计时器最常用的方法。

对于重复的任务:

new Timer().scheduleAtFixedRate(task, after, interval);

对于任务的单次运行:

new Timer().schedule(task, after);


任务是在初次执行
之后要执行的方法
间隔重复执行的时间)


9
我要补充一点,时间以毫秒为单位
Uri


1
task可能是您的类的实例,该类继承自java.util.TimerTask并重写void run()
n611x007

2
如此多的投票。你可以做到这一点。但是@Samuel描述了更好的方法。有关原因,请参见他的“此处解释了哪些内容”链接。另外,无法从Timer线程更新UI!并在其他线程中查看以下其他基于Handler的答案:(简单)stackoverflow.com/a/6702767/199364,或(显示各种选择)stackoverflow.com/a/4598737/199364
ToolmakerSteve 2014年

@quemeful因为它并不总是与便利有关,而是与代码质量和效率有关。这种方式使用的是处理程序,因此使用了更多的资源
inDepth

33

我希望这对您有所帮助,并且可以花费更少的精力来实现, Android CountDownTimer类

例如

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

      public void onFinish() {
          mTextField.setText("done!");
      }  
}.start();

1
这是最简单的方法,击中头部
后就可以

17

大概 Timerconcept

new CountDownTimer(40000, 1000) { //40000 milli seconds is total time, 1000 milli seconds is time interval

 public void onTick(long millisUntilFinished) {
  }
  public void onFinish() {
 }
}.start();

要么

方法2 ::

设定计时器

添加一个名为int的int新变量。将其设置为0。将以下代码添加到MainActivity.java中的onCreate函数。

//Declare the timer
Timer t = new Timer();
//Set the schedule function and rate
t.scheduleAtFixedRate(new TimerTask() {

    @Override
    public void run() {
        //Called each time when 1000 milliseconds (1 second) (the period parameter)
    }

},
//Set how long before to start calling the TimerTask (in milliseconds)
0,
//Set the amount of time between each execution (in milliseconds)
1000);

进入run方法并添加以下代码。

//We must use this function in order to change the text view text
runOnUiThread(new Runnable() {

    @Override
    public void run() {
        TextView tv = (TextView) findViewById(R.id.main_timer_text);
        tv.setText(String.valueOf(time));
        time += 1;
    }

});

11

这是情境。

Android文档建议您使用AlarmManager注册一个Intent,如果您的应用程序可能未运行,则该Intent将在指定的时间触发。

否则,您应该使用Handler。

注意:警报管理器适用于希望在特定时间运行应用程序代码的情况,即使您的应用程序当前未运行。对于正常的计时操作(滴答声,超时等),使用Handler会更容易且效率更高。


11

我们开始。.我们将需要两个班。我发布了一个代码,该代码每5秒钟(5000毫秒)后会更改移动音频配置文件...

我们的一等舱

public class ChangeProfileActivityMain extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);

        Timer timer = new Timer();
        TimerTask updateProfile = new CustomTimerTask(ChangeProfileActivityMain.this);
        timer.scheduleAtFixedRate(updateProfile, 0, 5000);
    }

}

我们的二等班

public class CustomTimerTask extends TimerTask {

    private AudioManager audioManager;
    private Context context;
    private Handler mHandler = new Handler();

    // Write Custom Constructor to pass Context
    public CustomTimerTask(Context con) {
        this.context = con;
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub

        // your code starts here.
        // I have used Thread and Handler as we can not show Toast without starting new thread when we are inside a thread.
        // As TimePicker has run() thread running., So We must show Toast through Handler.post in a new Thread. Thats how it works in Android..
        new Thread(new Runnable() {
            @Override
            public void run() {
                audioManager = (AudioManager) context.getApplicationContext().getSystemService(Context.AUDIO_SERVICE);
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        if(audioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT) {
                            audioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
                            Toast.makeText(context, "Ringer Mode set to Normal", Toast.LENGTH_SHORT).show();
                        } else {
                            audioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
                            Toast.makeText(context, "Ringer Mode set to Silent", Toast.LENGTH_SHORT).show();
                        }
                    }
                });
            }
        }).start();

    }

}

5

我是一名Android新手,但这是我根据上述答案创建的计时器类。它适用于我的应用程序,但是我欢迎任何建议。

用法示例:

...{
public Handler uiHandler = new Handler();

  private Runnable runMethod = new Runnable()
    {
        public void run()
        {
              // do something
        }
    };

    timer = new UITimer(handler, runMethod, timeoutSeconds*1000);       
        timer.start();
}...

public class UITimer
{
    private Handler handler;
    private Runnable runMethod;
    private int intervalMs;
    private boolean enabled = false;
    private boolean oneTime = false;

    public UITimer(Handler handler, Runnable runMethod, int intervalMs)
    {
        this.handler = handler;
        this.runMethod = runMethod;
        this.intervalMs = intervalMs;
    }

    public UITimer(Handler handler, Runnable runMethod, int intervalMs, boolean oneTime)
    {
        this(handler, runMethod, intervalMs);
        this.oneTime = oneTime;
    }

    public void start()
    {
        if (enabled)
            return;

        if (intervalMs < 1)
        {
            Log.e("timer start", "Invalid interval:" + intervalMs);
            return;
        }

        enabled = true;
        handler.postDelayed(timer_tick, intervalMs);        
    }

    public void stop()
    {
        if (!enabled)
            return;

        enabled = false;
        handler.removeCallbacks(runMethod);
        handler.removeCallbacks(timer_tick);
    }

    public boolean isEnabled()
    {
        return enabled;
    }

    private Runnable timer_tick = new Runnable()
    {
        public void run()
        {
            if (!enabled)
                return;

            handler.post(runMethod);

            if (oneTime)
            {
                enabled = false;
                return;
            }

            handler.postDelayed(timer_tick, intervalMs);
        }
    }; 
}

3

我正在使用处理程序并且可运行以创建计时器。我将其包装在一个抽象类中。只需派生/实现它,您就可以做好了:

 public static abstract class SimpleTimer {
    abstract void onTimer();

    private Runnable runnableCode = null;
    private Handler handler = new Handler();

    void startDelayed(final int intervalMS, int delayMS) {
        runnableCode = new Runnable() {
            @Override
            public void run() {
                handler.postDelayed(runnableCode, intervalMS);
                onTimer();
            }
        };
        handler.postDelayed(runnableCode, delayMS);
    }

    void start(final int intervalMS) {
        startDelayed(intervalMS, 0);
    }

    void stop() {
        handler.removeCallbacks(runnableCode);
    }
}

请注意,在handler.postDelayed要执行的代码之前调用了-这将使计时器更加封闭地计时为“预期”。但是,如果计时器运行频繁且任务(onTimer())很长-可能会有重叠。如果要intervalMS在任务完成后开始计数,请将onTimer()呼叫移到上方一行。



1

我以前用(TimerTimerTask),以及Handler揭开序幕(耗时)定期任务。现在,我将整个切换到RxJava。RxJava提供了Observable.timer更简单,更不易出错且易于使用的方法。

public class BetterTimerFragment extends Fragment {
  public static final String TAG = "BetterTimer";
  private TextView timeView;
  private Subscription timerSubscription;

  @Override
  public View onCreateView(LayoutInflater inflater,
                           @Nullable ViewGroup container,
                           @Nullable Bundle savedInstanceState) {
    return inflater.inflate(R.layout.fragment_timer, container, false);
  }

  @Override
  public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    timeView = (TextView) view.findViewById(R.id.timeView);
  }

  @Override
  public void onResume() {
    super.onResume();

    // Right after the app is visible to users, delay 2 seconds
    // then kick off a (heavy) task every 10 seconds.
    timerSubscription = Observable.timer(2, 10, TimeUnit.SECONDS)
        .map(new Func1<Long, String>() {
          @Override
          public String call(Long unused) {
            // TODO: Probably do time-consuming work here.
            // This runs on a different thread than the main thread.
            return "Time: " + System.currentTimeMillis();
          }
        })
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Action1<String>() {
          @Override
          public void call(String timeText) {
            // The result will then be propagated back to the main thread.
            timeView.setText(timeText);
          }
        }, new Action1<Throwable>() {
          @Override
          public void call(Throwable throwable) {
            Log.e(TAG, throwable.getMessage(), throwable);
          }
        });
  }

  @Override
  public void onPause() {
    super.onPause();

    // Don't kick off tasks when the app gets invisible.
    timerSubscription.unsubscribe();
  }
}

1

对于计时操作,应使用Handler

如果您需要运行后台服务,则可以使用AlarmManager。


0

本示例启动在Kotlin中销毁的计时器unitl

private lateinit var timerTask: TimerTask

 timerTask = object : TimerTask() {
        override fun run() {
            Log.d("KTZ", "$minutes:$seconds");
            timeRecordingLiveData.postValue("$minutes:$seconds")
            seconds += 1;
            if (seconds == 60) {
                Log.d("KTZ", "$minutes:$seconds");
                timeRecordingLiveData.postValue("$minutes:$seconds")
                seconds = 0;
                minutes += 1;
            }
        }

    }

取消onDestroy()中的timertask

timerTask.cancel()
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.