有人能给出一个简单的例子,每秒钟更新一个文本框左右?

我想要制作一个飞行的球,并需要每秒计算/更新球的坐标,这就是为什么我需要某种计时器。

我从这里什么也得不到。


当前回答

我很惊讶,没有答案会提到RxJava2的解决方案。它真的很简单,提供了一个简单的方法来设置计时器在Android。

首先你需要设置Gradle依赖,如果你还没有这样做:

implementation "io.reactivex.rxjava2:rxjava:2.x.y"

(将x和y替换为当前版本号)

因为我们只有一个简单的,非重复的TASK,我们可以使用Completable对象:

Completable.timer(2, TimeUnit.SECONDS, Schedulers.computation())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(() -> {
            // Timer finished, do something...
        });

对于重复TASK,你可以用类似的方式使用Observable:

Observable.interval(2, TimeUnit.SECONDS, Schedulers.computation())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(tick -> {
            // called every 2 seconds, do something...
        }, throwable -> {
            // handle error
        });

Schedulers.computation()确保我们的计时器在后台线程上运行,. observveon (AndroidSchedulers.mainThread())意味着我们在计时器结束后运行的代码将在主线程上完成。

为了避免不必要的内存泄漏,您应该确保在Activity/Fragment被销毁时取消订阅。

其他回答

这里是解决方案,您需要在代码中添加以下类。您可以直接向XML文件添加视图。

import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
import android.widget.TextView;

import java.util.Locale;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;

public class TimerTextView extends TextView {

    private static final int DEFAULT_INTERVAL = 1000;

    private Timer timer = new Timer();
    private long endTime = 0;
    private long interval = DEFAULT_INTERVAL;
    private boolean isCanceled = false;

    public TimerTextView(Context context) {
        super(context);
    }

    public TimerTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public TimerTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public TimerTextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        stopTimer();
    }

    @Override protected void onVisibilityChanged(View changedView, int visibility) {
        super.onVisibilityChanged(changedView, visibility);
        if (VISIBLE == visibility) {
            startTimer();
        } else {
            stopTimer();
        }
    }

    public void setInterval(long interval) {
        if (interval >= 0) {
            this.interval = interval;
            stopTimer();
            startTimer();
        }
    }

    public void setEndTime(long endTime) {
        if (endTime >= 0) {
            this.endTime = endTime;
            stopTimer();
            startTimer();
        }
    }

    private void startTimer() {
        if (endTime == 0) {
            return;
        }
        if (isCanceled) {
            timer = new Timer();
            isCanceled = false;
        }
        timer.scheduleAtFixedRate(new TimerTask() {
            @Override public void run() {
                if (null == getHandler()) {
                    return;
                }
                getHandler().post(new Runnable() {
                    @Override public void run() {
                        setText(getDurationBreakdown(endTime - System.currentTimeMillis()));
                    }
                });
            }
        }, 0, interval);
    }

    private void stopTimer() {
        timer.cancel();
        isCanceled = true;
    }

    private String getDurationBreakdown(long diff) {
        long millis = diff;
        if (millis < 0) {
            return "00:00:00";
        }
        long hours = TimeUnit.MILLISECONDS.toHours(millis);
        millis -= TimeUnit.HOURS.toMillis(hours);
        long minutes = TimeUnit.MILLISECONDS.toMinutes(millis);
        millis -= TimeUnit.MINUTES.toMillis(minutes);
        long seconds = TimeUnit.MILLISECONDS.toSeconds(millis);


        return String.format(Locale.ENGLISH, "%02d:%02d:%02d", hours, minutes, seconds);
        //return "${getWithLeadZero(hours)}:${getWithLeadZero(minutes)}:${getWithLeadZero(seconds)}"
    }
}

如果你已经有了时间。

public class Timer {
    private float lastFrameChanged;
    private float frameDuration;
    private Runnable r;

    public Timer(float frameDuration, Runnable r) {
        this.frameDuration = frameDuration;
        this.lastFrameChanged = 0;
        this.r = r;
    }

    public void update(float dt) {
        lastFrameChanged += dt;

        if (lastFrameChanged > frameDuration) {
            lastFrameChanged = 0;
            r.run();
        }
    }
}

你也可以使用动画器:

int secondsToRun = 999;

ValueAnimator timer = ValueAnimator.ofInt(secondsToRun);
timer.setDuration(secondsToRun * 1000).setInterpolator(new LinearInterpolator());
timer.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
    {
        @Override
        public void onAnimationUpdate(ValueAnimator animation)
        {
            int elapsedSeconds = (int) animation.getAnimatedValue();
            int minutes = elapsedSeconds / 60;
            int seconds = elapsedSeconds % 60;

            textView.setText(String.format("%d:%02d", minutes, seconds));
        }
    });
timer.start();

对于想要在kotlin中这样做的人:

val timer = fixedRateTimer(period = 1000L) {
            val currentTime: Date = Calendar.getInstance().time
            runOnUiThread {
                tvFOO.text = currentTime.toString()
            }
        }

为了停止计时器,你可以使用这个:

timer.cancel()

这个函数有许多其他选项,请尝试一下

我认为你可以用Rx方法来做:

 timerSubscribe = Observable.interval(1, TimeUnit.SECONDS)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Action1<Long>() {
                @Override
                public void call(Long aLong) {
                      //TODO do your stuff
                }
            });

然后取消这个:

timerSubscribe.unsubscribe();

接收定时器 http://reactivex.io/documentation/operators/timer.html