Android:计时器作为持久的秒表。如何设置开始时间?什么是天文台“基础”?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2324701/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 05:25:52  来源:igfitidea点击:

Android: chronometer as a persistent stopwatch. How to set starting time? What is Chronometer "Base"?

androidchronometer

提问by Santiago

I do have one service running in the background. Whenever it starts I store in memory the starting time in milliseconds:

我确实有一项服务在后台运行。每当它启动时,我都会在内存中存储以毫秒为单位的启动时间:

startingTime = new Date().getTime();

I want to display a chronometer that starts counting when the service starts and never stops until the user presses a button. I want to allow the user to leave the activity rendering the chronometer, do some stuff and then return. But the idea is that when the user returns I dont want the chronometer to go to 0:00 again. Insted I want it to show the exact time that has passed ever since the service has started.

我想显示一个计时器,它在服务启动时开始计数,并且在用户按下按钮之前永远不会停止。我想让用户离开呈现计时器的活动,做一些事情然后返回。但这个想法是,当用户返回时,我不希望天文钟再次回到 0:00。Insted 我希望它显示自服务启动以来经过的确切时间。

I can calculate elapsedTime every time the user return to the chronometer activity:

每次用户返回计时器活动时,我都可以计算 elapsedTime:

elapsedTime =  new Date().getTime() - startingTime;

The thing is that i dont know how to tell the chronometer to start counting from that time!

问题是我不知道如何告诉天文台从那个时候开始计数!

Setting it as the chronometer base does not work. Can someon explain what exactly "base" means or how to accomplish this?

将其设置为天文台底座不起作用。有人可以解释一下“基础”究竟是什么意思或如何做到这一点?

thanks a lot! BYE

多谢!再见

回答by Macarse

You can use Chronometer.

您可以使用天文台

You should also check this thread.

您还应该检查此线程

EDIT: The solution:

编辑:解决方案:

public class ChronoExample extends Activity {
 Chronometer mChronometer;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);

     LinearLayout layout = new LinearLayout(this);
     layout.setOrientation(LinearLayout.VERTICAL);

     mChronometer = new Chronometer(this);

     // Set the initial value
     mChronometer.setText("00:10");
     layout.addView(mChronometer);

     Button startButton = new Button(this);
     startButton.setText("Start");
     startButton.setOnClickListener(mStartListener);
     layout.addView(startButton);

     Button stopButton = new Button(this);
     stopButton.setText("Stop");
     stopButton.setOnClickListener(mStopListener);
     layout.addView(stopButton);

     Button resetButton = new Button(this);
     resetButton.setText("Reset");
     resetButton.setOnClickListener(mResetListener);
     layout.addView(resetButton);        

     setContentView(layout);
 }

 private void showElapsedTime() {
     long elapsedMillis = SystemClock.elapsedRealtime() - mChronometer.getBase();            
     Toast.makeText(ChronoExample.this, "Elapsed milliseconds: " + elapsedMillis, 
             Toast.LENGTH_SHORT).show();
 }

 View.OnClickListener mStartListener = new OnClickListener() {
     public void onClick(View v) {
      int stoppedMilliseconds = 0;

         String chronoText = mChronometer.getText().toString();
         String array[] = chronoText.split(":");
         if (array.length == 2) {
           stoppedMilliseconds = Integer.parseInt(array[0]) * 60 * 1000
               + Integer.parseInt(array[1]) * 1000;
         } else if (array.length == 3) {
           stoppedMilliseconds = Integer.parseInt(array[0]) * 60 * 60 * 1000 
               + Integer.parseInt(array[1]) * 60 * 1000
               + Integer.parseInt(array[2]) * 1000;
         }

         mChronometer.setBase(SystemClock.elapsedRealtime() - stoppedMilliseconds);
         mChronometer.start();
     }
 };

 View.OnClickListener mStopListener = new OnClickListener() {
     public void onClick(View v) {
         mChronometer.stop();
         showElapsedTime();
     }
 };

 View.OnClickListener mResetListener = new OnClickListener() {
     public void onClick(View v) {
         mChronometer.setBase(SystemClock.elapsedRealtime());
         showElapsedTime();
     }
 };
}

回答by Elcresan

To start the chronometer you should use the setBase()method of your chronometer with SystemClock.elapsedRealTime(). Just like this:

要启动计时器,您应该使用setBase()带有 的计时器的方法SystemClock.elapsedRealTime()。像这样:

mChronometer.setBase(SystemClock.elapsedRealTime())

But if you want to start at another time, you have to subtract the time you want in milliseconds. For example, you want to start your Chronometer at 10 seconds:

但是如果你想在另一个时间开始,你必须以毫秒为单位减去你想要的时间。例如,您想在 10 秒时启动您的天文台:

mChronometer.setBase(SystemClock.elapsedRealTime() - 10*1000);

At 2 minutes:

2 分钟时:

mChronometer.setBase(SystemClock.elapsedRealTime() - 2*60*1000);

But the problem here is that the Chronometer will show "00:00" time before it start to count, to change it to your time you have to do that :

但这里的问题是,天文台会在开始计数之前显示“00:00”时间,要将其更改为您的时间,您必须这样做:

mChronometer.setText("02:00");

回答by Graeme Duncan

The base time is the time that the Chronometerstarted ticking at. You can set it using Chronometer.setBase(). You should get the base time by using SystemClock.getElapsedTime(). Call setBase()with the start time each time the Chronometeris started. If there is potential for the Activityto be destroyed and recreated while the timer is still active then you will need to hold the base time somewhere outside of the Activitythat owns the Chronometer.

基准时间是Chronometer开始滴答的时间。您可以使用Chronometer.setBase(). 您应该使用SystemClock.getElapsedTime(). setBase()每次启动时调用开始时间Chronometer。如果有潜在的Activity被破坏和重建,而计时器仍处于活动状态,那么你将需要持有的基本时间之外的某个地方Activity拥有的Chronometer

回答by Serhii Bohutskyi

Some strange with SystemClock.getElapsedTime(), I did some changes for normal using with start date, like

SystemClock.getElapsedTime() 有点奇怪,我对开始日期的正常使用做了一些更改,比如

myChron.setBase(startDate.getTime());

Here child of Chronometer below, TimeView

下面是 Chronometer 的孩子,TimeView

import android.R;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.text.format.DateUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.Chronometer;
import android.widget.RemoteViews;

import java.util.Formatter;
import java.util.IllegalFormatException;
import java.util.Locale;

@RemoteViews.RemoteView
public class TimeView extends Chronometer {
    private static final String TAG = "TimeView";

    private long mBase;
    private boolean mVisible;
    private boolean mStarted;
    private boolean mRunning;
    private boolean mLogged;
    private String mFormat;
    private Formatter mFormatter;
    private Locale mFormatterLocale;
    private Object[] mFormatterArgs = new Object[1];
    private StringBuilder mFormatBuilder;
    private OnChronometerTickListener mOnChronometerTickListener;
    private StringBuilder mRecycle = new StringBuilder(8);

    private static final int TICK_WHAT = 2;

    /**
     * Initialize this Chronometer object.
     * Sets the base to the current time.
     */
    public TimeView(Context context) {
        this(context, null, 0);
    }

    /**
     * Initialize with standard view layout information.
     * Sets the base to the current time.
     */
    public TimeView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    /**
     * Initialize with standard view layout information and style.
     * Sets the base to the current time.
     */
    public TimeView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    private void init() {
        mBase = System.currentTimeMillis();
        updateText(mBase);
    }

    public void setBase(long base) {
        mBase = base;
        dispatchChronometerTick();
        updateText(System.currentTimeMillis());
    }

    /**
     * Return the base time as set through {@link #setBase}.
     */
    public long getBase() {
        return mBase;
    }

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

    /**
     * Stop counting up.  This does not affect the base as set from {@link #setBase}, just
     * the view display.
     * <p/>
     * This stops the messages to the handler, effectively releasing resources that would
     * be held as the chronometer is running, via {@link #start}.
     */
    public void stop() {
        mStarted = false;
        updateRunning();
    }

    /**
     * The same as calling {@link #start} or {@link #stop}.
     *
     * @hide pending API council approval
     */
    public void setStarted(boolean started) {
        mStarted = started;
        updateRunning();
    }

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

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

    private synchronized void updateText(long now) {
        long seconds = now - mBase;
        seconds /= 1000;
        String text = DateUtils.formatElapsedTime(mRecycle, seconds);

        if (mFormat != null) {
            Locale loc = Locale.getDefault();
            if (mFormatter == null || !loc.equals(mFormatterLocale)) {
                mFormatterLocale = loc;
                mFormatter = new Formatter(mFormatBuilder, loc);
            }
            mFormatBuilder.setLength(0);
            mFormatterArgs[0] = text;
            try {
                mFormatter.format(mFormat, mFormatterArgs);
                text = mFormatBuilder.toString();
            } catch (IllegalFormatException ex) {
                if (!mLogged) {
                    Log.w(TAG, "Illegal format string: " + mFormat);
                    mLogged = true;
                }
            }
        }
        setText(text);
    }

    private void updateRunning() {
        boolean running = mVisible && mStarted;
        if (running != mRunning) {
            if (running) {
                updateText(System.currentTimeMillis());
                dispatchChronometerTick();
                mHandler.sendMessageDelayed(Message.obtain(mHandler, TICK_WHAT), 1000);
            } else {
                mHandler.removeMessages(TICK_WHAT);
            }
            mRunning = running;
        }
    }

    private Handler mHandler = new Handler() {
        public void handleMessage(Message m) {
            if (mRunning) {
                updateText(System.currentTimeMillis());
                dispatchChronometerTick();
                sendMessageDelayed(Message.obtain(this, TICK_WHAT), 1000);
            }
        }
    };

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

Just copy and use, it works for me

只需复制和使用,它对我有用

回答by faizal

This works for me :

这对我有用:

Date now = new Date();
long elapsedTime = now.getTime() - startTime.getTime(); //startTime is whatever time you want to start the chronometer from. you might have stored it somwehere
myChronometer.setBase(SystemClock.elapsedRealtime() - elapsedTime);
myChronometer.start();

回答by Caresth

When you set the basetime with .setBase(SystemClock.elapsedRealTime()) the chronomether starts to count from 00.00 but the time it stores is the amount of milisecs from boot. When you use .stop the internal count does not stop, just the time you see on the clock. So, if you use .start again, the clock count jumps to the real count. If you want to store the time that has passed from the start, you have to get again the System elapsed time and make the difference with the .setTime

当您使用 .setBase(SystemClock.elapsedRealTime()) 设置基准时间时,计时器从 00.00 开始计数,但它存储的时间是启动后的毫秒数。当您使用 .stop 时,内部计数不会停止,只是您在时钟上看到的时间。因此,如果您再次使用 .start,时钟计数将跳转到实际计数。如果要存储从一开始就过去的时间,则必须再次获取系统经过时间并与 .setTime 有所不同

回答by Jorgesys

How to set starting time? What is Chronometer “Base”?

如何设置开始时间?什么是天文台“基础”?

Use SystemClock.elapsedRealtime()for this purpose:

使用SystemClock.elapsedRealtime()用于此目的:

   myChronometer.setBase(SystemClock.elapsedRealtime());