天文台初始值错误

问题描述 投票:0回答:2

我编写了一个基于 android.widget.Chronometer 的简单国际象棋时钟应用程序。我将它与

setCountDown(true)
标志一起使用,并且所有逻辑都运行良好。每个天文台表都在单独的
Fragment
中创建。但有时天文台初始值会出现一些问题。例如,我将初始值设置为 20 秒,但实际上我有这个: 在应用程序重新启动时,这种区别可能是在随机时钟上。我这样设置初始值,在我的类中扩展
android.widget.Chronometer
,并且mTimeLimit每次等于20000:

private void setTimeLimit() {
    mStartTime = SystemClock.elapsedRealtime() + mTimeLimit;
    setBase(mStartTime);
}

我认为问题可能出在片段创建时间等方面。谁知道我错了什么?

java android android-widget
2个回答
0
投票

我通过在初始值上添加 100 millis 找到了一个解决方案:

mStartTime = SystemClock.elapsedRealtime() + mTimeLimit + 100;

似乎它解决了问题,但我认为这不是最好的决定,也许有人知道更好的方法。


0
投票

出现问题的原因是 Chronometer 类通过截断毫秒的除法来计算秒,而它应该对结果进行四舍五入。

这在向上计数时不是问题,但在向下计数时却是问题。

我在问题跟踪器上打开了一个问题,请求修改 Chronometer 类中的计算:

https://issuetracker.google.com/issues/297733248

在计时器的基础上添加任意数量的毫秒可能在某些设备中有效,但在速度较慢的设备中,问题可能仍然会发生。

我的解决方案(当问题在问题跟踪器中得到解决时)是基于框架的 Chronometer 类创建一个自定义的“MyChronometer”类,但具有正确的计算(请参阅“updateText”方法中的计算):

@SuppressLint("AppCompatCustomView")
@RemoteView
public class MyChronometer extends TextView {

    public interface OnChronometerTickListener {
        void onChronometerTick(MyChronometer chronometer);
    }

    private long mBase;
    private boolean mVisible;
    private boolean mStarted;
    private boolean mRunning;
    private final StringBuilder mRecycle = new StringBuilder(8);
    private OnChronometerTickListener mOnChronometerTickListener;
    private boolean mCountDown;

    public MyChronometer(Context context) {
        this(context, null, 0);
    }

    public MyChronometer(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyChronometer(Context context, AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
    }

    public MyChronometer(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init();
    }

    private void init() {
        mBase = SystemClock.elapsedRealtime();
        updateText(mBase);
    }

    public void setCountDown(boolean countDown) {
        mCountDown = countDown;
        updateText(SystemClock.elapsedRealtime());
    }

    public void setBase(long base) {
        mBase = base;
        dispatchChronometerTick();
        updateText(SystemClock.elapsedRealtime());
    }

    public long getBase() {
        return mBase;
    }

    public void setOnChronometerTickListener(OnChronometerTickListener listener) {
        mOnChronometerTickListener = listener;
    }

    public OnChronometerTickListener getOnChronometerTickListener() {
        return mOnChronometerTickListener;
    }

    public void start() {
        mStarted = true;
        updateRunning();
    }

    public void stop() {
        mStarted = false;
        updateRunning();
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        mVisible = false;
        updateRunning();
    }

    @Override
    protected void onWindowVisibilityChanged(int visibility) {
        super.onWindowVisibilityChanged(visibility);
        mVisible = visibility == VISIBLE;
        updateRunning();
    }

    @Override
    protected void onVisibilityChanged(View changedView, int visibility) {
        super.onVisibilityChanged(changedView, visibility);
        updateRunning();
    }

    private synchronized void updateText(long now) {

        long diffMillis = mCountDown ? mBase - now : now - mBase;
        int seconds = Math.round(diffMillis / 1000f);

        String text;

        if (seconds < 0) {
            text = "-" + DateUtils.formatElapsedTime(mRecycle, -seconds);
        } else {
            text = DateUtils.formatElapsedTime(mRecycle, seconds);
        }

        setText(text);

    }

    private void updateRunning() {

        boolean running = mVisible && mStarted && isShown();

        if (running != mRunning) {

            if (running) {
                updateText(SystemClock.elapsedRealtime());
                dispatchChronometerTick();
                postDelayed(mTickRunnable, 1000);
            } else {
                removeCallbacks(mTickRunnable);
            }

            mRunning = running;

        }

    }

    private final Runnable mTickRunnable = new Runnable() {
        @Override
        public void run() {
            if (mRunning) {
                updateText(SystemClock.elapsedRealtime());
                dispatchChronometerTick();
                postDelayed(mTickRunnable, 1000);
            }
        }
    };

    void dispatchChronometerTick() {
        if (mOnChronometerTickListener != null) {
            mOnChronometerTickListener.onChronometerTick(this);
        }
    }

    @Override
    public CharSequence getAccessibilityClassName() {
        return MyChronometer.class.getName();
    }

}
© www.soinside.com 2019 - 2024. All rights reserved.