使用Runnable和postDelayed更新UI在计时器应用程序中不起作用

23
我已经查看了所有与此相关的讨论和线程,但还是无法使它工作。我有一个简单的计时器,可以更新文本视图(在下面的示例中为mTimeTextField)。mUpdateTimeTask运行方法被正确执行(每秒一次),但UI / 文本字段未被更新。
我基于此处找到的信息编写了代码:

http://android-developers.blogspot.com/2007/11/stitch-in-time.html http://developer.android.com/resources/articles/timed-ui-updates.html

这里是代码:

package com.something.handlertest;

import com.something.handlertest.R;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class Test extends Activity {

    private Handler mHandler = new Handler(); 
    private int labelNo    = 0;
    private long currTime  = 0L;
    private long mStartTime = 0L;
    TextView mTimeTextField;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mTimeTextField = (TextView)findViewById(R.id.timeTextFieldl);

        Button startButton = (Button)findViewById(R.id.start_button);
        startButton.setOnClickListener(new View.OnClickListener() {

            public void onClick(View v) {
                   if (mStartTime == 0L) {
                        mStartTime = System.currentTimeMillis();
                        mHandler.removeCallbacks(mUpdateTimeTask);
                        mHandler.postDelayed(mUpdateTimeTask, 100);
                   }
            }
        });
    }

    private Runnable mUpdateTimeTask = new Runnable() {
           public void run() {
               final long start = mStartTime;
               //long millis = SystemClock.uptimeMillis() - start;
               long millis = SystemClock.uptimeMillis();
               int seconds = (int) (millis / 1000);
               int minutes = seconds / 60;
               seconds     = seconds % 60;

               //setContentView(mTimeTextField);  This will blow up if I use it

               if (seconds < 10) {
                   mTimeTextField.setText("" + minutes + ":0" + seconds);
               } else {
                   mTimeTextField.setText("" + minutes + ":" + seconds);            
               }

               //mHandler.postAtTime(this,
                   //    start + (((minutes * 60) + seconds + 1) * 1000));

               mHandler.postAtTime(this, 1000);
           }
        };

}

根据一些建议,我尝试添加了:

setContentView(mTimeLabel);

但这会导致崩溃,抱怨视图没有父视图。顺便说一下,我确实有一个:

setContentView(R.layout.main);

在我的onCreate()中调用。


你尝试过在这里提到的runOnUiThread吗?http://stackoverflow.com/questions/3741458/change-imageview-after-few-seconds/3741643#3741643 - Mathias Conradt
将contentView设置为textview绝对是不正确的。只有将content view设置为布局才有意义,因为你已经在onCreate方法中这样做了。 - Mathias Conradt
6个回答

19
mHandler.postAtTime(this, 1000);

使用

mHandler.postDelayed(this, 1000);

成功了!!!我刚刚按照你上面建议的修改了代码。我不确定为什么Dick Wall的示例代码中使用了postAtTime,但我很感激它现在能够工作了。Fedor--非常感谢!!! - bdelliott
嗯,这可能有效。但问题是,这是否是你真正想要的。如果你想在两个时刻之间精确地发生某些事情,postDelayed 可能不是你想要的。postDelayed 将在语句执行的时间瞬间后 "x" 毫秒运行可运行对象。而 postAtTime 则不同。 - VJ Vélan Solutions

5
  1. You need to do UI updates in the UI thread.
  2. You need to create a Handler in the UI thread to run tasks in the UI thread.

    public class MainActivity extends AppCompatActivity
        private Handler mHandler;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            mHandler = new Handler(); // This to create the Handler in the UI thread
            // ...
        }
    

4
这可能更符合您的需求:

这可能更符合您的要求:

private Runnable mUpdateTimeTask = new Runnable() {
       public void run() {

           final long start = mStartTime;
           long elapseTime = System.currentTimeMillis() - start;
           int seconds = (int) (elapseTime / 1000);
           int minutes = seconds / 60;
           seconds     = seconds % 60;

           if (seconds < 10) {
               mTimeTextField.setText("" + minutes + ":0" + seconds);
           } else {
               mTimeTextField.setText("" + minutes + ":" + seconds);            
           }

           // add a delay to adjust for computation time
           long delay = (1000 - (elapseTime%1000));

           mHandler.postDelayed(this, delay);
       }
    };

我发现这是给视频添加时间的一种好方法


1

视图只能在UI线程上显示。您必须使用ru启动可运行程序。


0
请确保 R.id.timeTextFieldl 是正确的 ID。

0
if (seconds < 10) {
    mTimeTextField.setText("" + minutes + ":0" + seconds);
} else {
    mTimeTextField.setText("" + minutes + ":" + seconds);            
}

更短的是:

mTimeTextField.setText(minutes + ":" + (seconds < 10 ? "0" : "") + seconds);

但更好的方法是使用String.format

mTimeTextField.setText(String.format("%d:%s%d", minutes, (seconds < 10 ? "0" : ""), seconds);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接