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

Я пытаюсь сделать часы, используя TextView :)

Кто-то здесь сказал мне, что я не могу использовать обычные потоки для изменения пользовательского интерфейса, но Handler или AsyncTask. Мне удалось заставить его работать несколько дней назад, но это не было последовательным потоком.

Теперь мне нужен согласованный поток, который всегда меняет текст моего Textview. Я пытался использовать это, но не сработало, любая помощь?

private void startClock() {
    new Handler().postDelayed(new Runnable(){

        @Override
        public void run() {
            while (true) {
                final long millis = System.currentTimeMillis() - MainActivity.startedAt;
                clock.setText("" + millis);
                runOnUiThread (new Runnable() {

                    @Override
                    public void run() {
                        clock.setText("" + millis);
                    }
                });

                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }, 2000);
}

person TiagoM    schedule 10.03.2013    source источник
comment
Почему бы вместо этого не использовать класс Timer? Сделал бы вашу жизнь намного проще. См. здесь: stackoverflow.com/questions/15317600/   -  person Tyler MacDonell    schedule 10.03.2013
comment
Это может быть решением, не знал о классе Timer, но это только для одного запуска, верно? Я хочу, чтобы часы всегда работали.. Мне нужно было бы несколько раз вызывать Таймер, и это могло бы вызвать у меня такое же зависание.. спасибо за ваш ответ! очень ценю;) всегда люди помогают здесь :)   -  person TiagoM    schedule 10.03.2013
comment
Нет, вы можете запланировать повторные запуски через равные промежутки времени, и большую часть логики он сделает за вас.   -  person Tyler MacDonell    schedule 10.03.2013
comment
Как кстати? Просто звонить несколько раз? как внутри цикла? но я не могу использовать while(true), другой парень из принятого ответа сказал мне:/   -  person TiagoM    schedule 10.03.2013
comment
По сути, вы просто передаете Timer функцию обратного вызова, называемую TimerTask, и задаете ей регулярный интервал для выполнения TimerTask. Никаких петель не требуется. Пожалуйста, смотрите вопрос, который я связал для получения более подробной информации...   -  person Tyler MacDonell    schedule 10.03.2013
comment
Хм, я понял, Таймер повторяет одну и ту же задачу, пока вы не вызовете метод отмены на таймере, верно? Это тоже хорошо, спасибо, что поделились информацией :)   -  person TiagoM    schedule 10.03.2013


Ответы (2)


вам следует избавиться от:

while(true) {
    ....
    sleep(1000);
    ...
}

потому что это навсегда застрянет в вашей теме. ваша программа должна работать так:

private Handler mHandler = new Handler();

@Override
public void onResume() {
    super.onResume();
    mHandler.removeCallbacks(mUpdateClockTask);
    mHandler.postDelayed(mUpdateCLockTask, 100);
}

@Override
public void onPause() {
    super.onPause();
    mHandler.removeCallbacks(mUpdateClockTask);
}

private Runnable mUpdateClockTask = new Runnable() {
    public void run() {
        updateClock();
        mHandler.postDelayed(mUpdateClockTask, 2000);
    }
};

и внутри updateClock() вы выполняете все свои обновления пользовательского интерфейса.

person lenik    schedule 10.03.2013
comment
Я не знал, что while true вызовет какие-либо проблемы... Я бы изменил это while(true) на while(toContinue()).. и проверил бы, будет ли активность все еще использоваться... и когда я бы изменить активность, toContinue() вернет false.. Не знал, что некоторое время (true) будет отставать от этого, но это имеет смысл.. потому что есть такие методы, как onResume и onPause.. Каждый раз, когда я меняю активность, но это странно.. , ПОТОМУ ЧТО я даже не изменил активность, и она зависла сразу после... - person TiagoM; 10.03.2013
comment
В любом случае большое спасибо lenik, вы решили мою проблему, но я хотел бы понять это, если это возможно :) - person TiagoM; 10.03.2013
comment
первое правило программирования для Android - никогда не используйте while(true), если где-то внутри нет четкого выхода, который сработает очень скоро. все ваши функции должны выполнять свою работу и возвращаться обратно как можно скорее. если что-то не готово -- оставьте это и проверьте еще раз, когда в следующий раз придете в то же место. используйте обратные вызовы из системы и/или таймеры вместо ожидания. если есть что-то еще, что вы хотите, чтобы я объяснил, пожалуйста, задайте вопрос, это очень широкая тема, чтобы уместиться в 500 байт комментария =) - person lenik; 10.03.2013
comment
Привет, lenik, такие ребята, как ты, очень-очень приветствуются, большое спасибо. Вам не нужно повторять дважды, я новичок в программировании для Android, все еще учусь, у меня всего несколько дней. Но я не забуду, не тратьте время на методы, используйте колбэки и таймеры. Мне достаточно информации :) еще раз спасибо ;) - person TiagoM; 10.03.2013

Посмотрите здесь пример https://stackoverflow.com/a/11140429/808940

Также обратите внимание, что в вашем коде есть повторяющаяся строка:

clock.setText(""+millis);

Он появляется как в runOnUiThread, так и в основном обработчике, он должен появляться только в исполняемом файле runOnUiThread.

person Moog    schedule 10.03.2013
comment
@DarkLink Пожалуйста, не меняйте исходный код после того, как получите такой ответ. Я восстановил ваш код. - person ; 10.03.2013