如何在Android中每秒更改一次TextView

时间:2011-03-04 00:22:51

标签: android

我制作了一款简单的Android音乐播放器。我希望有一个TextView,以分钟为单位显示歌曲中的当前时间:秒格式。所以我尝试的第一件事就是让活动Runnable并把它放在run()中:

int position = 0;
while (MPService.getMP() != null && position<MPService.duration) {
try {
    Thread.sleep(1000);
    position = MPService.getSongPosition();
} catch (InterruptedException e) {
    return;
}

// ... convert position to formatted minutes:seconds string ...

currentTime.setText(time); // currentTime = (TextView) findViewById(R.id.current_time);

但是失败了,因为我只能在创建它的线程中触摸TextView。所以我尝试使用runOnUiThread(),但是这不起作用,因为在主线程上重复调用Thread.sleep(1000),因此活动只挂在空白屏幕上。那么我有什么想法可以解决这个问题呢?


新代码:

private int startTime = 0;
private Handler timeHandler = new Handler();
private Runnable updateTime = new Runnable() {
    public void run() {
        final int start = startTime;
        int millis = appService.getSongPosition() - start;
        int seconds = (int) ((millis / 1000) % 60);
        int minutes = (int) ((millis / 1000) / 60);
        Log.d("seconds",Integer.toString(seconds)); // no problem here
        if (seconds < 10) {
            // this is hit, yet the text never changes from the original value of 0:00
            currentTime.setText(String.format("%d:0%d",minutes,seconds));
        } else {
            currentTime.setText(String.format("%d:%d",minutes,seconds));
        }
        timeHandler.postAtTime(this,(((minutes*60)+seconds+1)*1000));
    }

};

private ServiceConnection onService = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
        IBinder rawBinder) {
      appService = ((MPService.LocalBinder)rawBinder).getService();

    // start playing the song, etc. 

    if (startTime == 0) {
        startTime = appService.getSongPosition();
        timeHandler.removeCallbacks(updateTime);
        timeHandler.postDelayed(updateTime,1000);
    }
}

5 个答案:

答案 0 :(得分:11)

怎么样:

    int delay = 5000; // delay for 5 sec.
    int period = 1000; // repeat every sec.

    Timer timer = new Timer();
    timer.scheduleAtFixedRate(new TimerTask()
        {
            public void run()
            {
                //your code
            }
        }, delay, period);

答案 1 :(得分:10)

为此使用Timer(而不是while循环,其中包含Thread.Sleep。有关如何使用计时器定期更新UI元素的示例,请参阅此文章:

Updating the UI from a timer

修改:更新后退链接,感谢Arialdohttp://web.archive.org/web/20100126090836/http://developer.android.com/intl/zh-TW/resources/articles/timed-ui-updates.html

修改2 :非回程链接,感谢gatoatigradohttp://android-developers.blogspot.com/2007/11/stitch-in-time.html

答案 2 :(得分:4)

您必须使用处理程序来处理与GUI的交互。特别是线程无法触及主线程上的任何内容。你在一个线程中做了一些事情,如果你需要在你的主线程中更改某些东西,那么你调用一个处理程序并在那里进行。

具体来说,它看起来像这样:

Thread t = new Thread(new Runnable(){ ... do stuff here

Handler.postMessage(); }

然后在代码的其他地方,你做

Handler h = new Handler(){

something something... modify ui element here }

想法就像这样,线程做了一些事情,通知处理程序,然后处理程序接受此消息,并执行更新UI线程上的textview。

答案 3 :(得分:0)

这是另一个Timer示例,我在我的项目中使用此代码。 https://stackoverflow.com/a/18028882/1265456

答案 4 :(得分:0)

我认为以下博客文章清楚地给出了一个非常好的解决方案。特别是,如果您是后台服务,并希望使用类似计时器的功能定期从此服务更新您的UI。 这对我来说真的很有帮助,远远超过MusiGenesis上面发布的2007年博客链接。

https://www.websmithing.com/2011/02/01/how-to-update-the-ui-in-an-android-activity-using-data-from-a-background-service/