Как изменить TextView каждую секунду в 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);
    }
}

Ответы

Ответ 1

Используйте Timer для этого (вместо цикла while с Thread.Sleep в нем). См. Эту статью для примера того, как периодически использовать таймер для обновления элемента интерфейса:

Обновление пользовательского интерфейса с помощью таймера

Изменить: обновленная обратная ссылка, благодаря Arialdo: http://web.archive.org/web/20100126090836/http://developer.android.com/intl/zh-TW/resources/articles/timed-ui-updates.html

Изменить 2: ссылка без обратного пути, благодаря gatoatigrado: http://android-developers.blogspot.com/2007/11/stitch-in-time.html p >

Ответ 2

что об этом:

    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);

Ответ 3

Вы должны использовать обработчик для взаимодействия с графическим интерфейсом. В частности, нить не может касаться НИЧЕГО на основной нити. Вы делаете что-то в потоке, и если вам нужно что-то изменить в своем основном потоке, вы вызываете обработчик и делаете его там.

В частности, это выглядит примерно так:

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

Handler.postMessage(); }

Затем где-то еще в вашем коде вы

Handler h = new Handler(){

something something... modify ui element here }

Идея, как это, поток что-то делает, уведомляет обработчика, обработчик затем принимает это сообщение и делает что-то вроде обновления текстового представления в потоке пользовательского интерфейса.

Ответ 4

Это еще один пример Timer, и я использую этот код в своем проекте. fooobar.com/questions/187355/...

Ответ 5

Я думаю, что приведенная ниже статья в блоге явно дает очень хорошее решение. Особенно, если вы являетесь справочной службой и хотите регулярно обновлять свой пользовательский интерфейс от этой службы, используя таймер. Это действительно помогло мне, гораздо больше, чем ссылка блога 2007 года, опубликованная MusiGenesis выше.

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