是否已经有适用于 android 的 StopWatch 类,为啥我的实现不起作用?

Posted

技术标签:

【中文标题】是否已经有适用于 android 的 StopWatch 类,为啥我的实现不起作用?【英文标题】:Is there already a StopWatch class for android and why doesn't my implementation work?是否已经有适用于 android 的 StopWatch 类,为什么我的实现不起作用? 【发布时间】:2014-03-25 18:21:15 【问题描述】:

最近我看到http://developer.android.com/reference/android/os/CountDownTimer.html 并想知道是否有相应的秒表类,因为我想告诉我的应用程序的用户他已经尝试解决这个难题多长时间了。我的意思是,自己编写这样的秒表并不复杂。我尝试了类似的东西

    Runnable runnable = new Runnable() 
        @Override
        public void run() 
            while (true) 
                try 
                    Thread.sleep(1000);
                 catch (InterruptedException e) 
                
                long seconds = (System.currentTimeMillis() - t) / 1000;
                statusBar.setText(String.format("%02d:%02d", seconds / 60, seconds % 60));
            
        

    ;
    statusBar.post(runnable);

但奇怪的是,我的活动布局不再膨胀,因为我在活动的 onCreate 方法的末尾有这个 statusBar.post(runnable);,这意味着在启动应用程序后我只看到一个白屏而不是正常的 gui。

【问题讨论】:

正确的做法是使用定时器。 你不能让主线程休眠。如果您在其他线程中运行此代码,您将需要一个处理程序来写入 UI(只有主线程可以更改 UI)。 【参考方案1】:

看看Chronometer 类。

来自 APIDemo 的示例代码:

import android.app.Activity;
import android.os.Bundle;
import android.os.SystemClock;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Chronometer;

public class ChronometerDemo extends Activity 
    Chronometer mChronometer;

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

        setContentView(R.layout.chronometer);

        Button button;

        mChronometer = (Chronometer) findViewById(R.id.chronometer);

        // Watch for button clicks.
        button = (Button) findViewById(R.id.start);
        button.setOnClickListener(mStartListener);

        button = (Button) findViewById(R.id.stop);
        button.setOnClickListener(mStopListener);

        button = (Button) findViewById(R.id.reset);
        button.setOnClickListener(mResetListener);

        button = (Button) findViewById(R.id.set_format);
        button.setOnClickListener(mSetFormatListener);

        button = (Button) findViewById(R.id.clear_format);
        button.setOnClickListener(mClearFormatListener);
    

    View.OnClickListener mStartListener = new OnClickListener() 
        public void onClick(View v) 
            mChronometer.start();
        
    ;

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

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

    View.OnClickListener mSetFormatListener = new OnClickListener() 
        public void onClick(View v) 
            mChronometer.setFormat("Formatted time (%s)");
        
    ;

    View.OnClickListener mClearFormatListener = new OnClickListener() 
        public void onClick(View v) 
            mChronometer.setFormat(null);
        
    ;

R.layout.chronometer:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:padding="4dip"
    android:gravity="center_horizontal"
    android:layout_
    android:layout_>

    <Chronometer android:id="@+id/chronometer"
        android:format="@string/chronometer_initial_format"
        android:layout_
        android:layout_
        android:layout_weight="0"
        android:paddingBottom="30dip"
        android:paddingTop="30dip"
        />

    <Button android:id="@+id/start"
        android:layout_
        android:layout_ 
        android:text="@string/chronometer_start">
        <requestFocus />
    </Button>

    <Button android:id="@+id/stop"
        android:layout_
        android:layout_ 
        android:text="@string/chronometer_stop">
    </Button>

    <Button android:id="@+id/reset"
        android:layout_
        android:layout_ 
        android:text="@string/chronometer_reset">
    </Button>

    <Button android:id="@+id/set_format"
        android:layout_
        android:layout_ 
        android:text="@string/chronometer_set_format">
    </Button>

    <Button android:id="@+id/clear_format"
        android:layout_
        android:layout_ 
        android:text="@string/chronometer_clear_format">
    </Button>

</LinearLayout>

将此添加到 Strings.xml

<string name="chronometer_start">Start</string>
<string name="chronometer_stop">Stop</string>
<string name="chronometer_reset">Reset</string>
<string name="chronometer_set_format">Set format string</string>
<string name="chronometer_clear_format">Clear format string</string>
<string name="chronometer_initial_format">Initial format: <xliff:g id="initial-format">%s</xliff:g></string>

【讨论】:

如果你也发布一个UI截图会不会更好:) 字符串 chronometer_initial_format 丢失,您能否将其添加到同一个答案中,以免我们去 Google 查看格式?【参考方案2】:

您应该使用天文台表。

但无论如何,如果您从 UI 线程中删除睡眠,您的代码仍然可以工作。

private final Runnable mRunnable = new Runnable() 
    @Override
    public void run() 
        if (mStarted) 
            long seconds = (System.currentTimeMillis() - t) / 1000;
            statusBar.setText(String.format("%02d:%02d", seconds / 60, seconds % 60));
            handler.postDelayed(runnable, 1000L);
        
    

;

private Hanlder mHandler;
private boolean mStarted;

@Override
protected void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    mHandler = new Handler();


@Override
protected void onStart() 
    super.onStart();
    mStarted = true;
    mHandler.postDealyed(runnable, 1000L);


@Override
protected void onStop() 
    super.onStop();
    mStarted = false;
    mHandler.removeCallbacks(mRunnable);

【讨论】:

@Ammaraly 只有 OP 知道,我首先修改了他的代码。 Chronometer 不支持秒表需要的暂停和恢复。【参考方案3】:

您应该使用Chronometer。

Chronometer mChronometer;
mChronometer = (Chronometer) findViewById(R.id.chronometer1);
long timeWhenStopped = 0;

当我们停止计时

timeWhenStopped = mChronometer.getBase() - SystemClock.elapsedRealtime();
mChronometer.stop();

启动前的计时器

mChronometer.setBase(SystemClock.elapsedRealtime() + timeWhenStopped);
mChronometer.start();

重置计时器

mChronometer.setBase(SystemClock.elapsedRealtime());
timeWhenStopped = 0;

【讨论】:

【参考方案4】:

为什么您的代码不起作用是因为您将 Runnable 发布到 UI 线程消息队列。 runnable 在while 循环中永远运行,阻止 UI 线程执行任何其他业务,例如绘制布局和响应输入。

在 UI 线程中使用 Thread.sleep() 几乎总是错误的。考虑改用Timer

【讨论】:

以上是关于是否已经有适用于 android 的 StopWatch 类,为啥我的实现不起作用?的主要内容,如果未能解决你的问题,请参考以下文章

是否有任何已发布的实施适用于 Android 的 Google Latitude API 的示例? [关闭]

适用于 Android 的计算机视觉和 AR 库?

适用于 Android 和 iOS 应用程序的 WebSockets

是否有任何适用于 android 的开源增强现实 sdk? [关闭]

适用于 Android 的超级任天堂模拟器

是否有适用于 Android 的 *** 提供程序 API? [关闭]