Представление Android не обновляется при попытке установить значения во времени

Я получил фрагмент, который получил элемент управления RingProgress это просто кольцо, которое заполняется в соответствии с заданным процентным значением. Например, если я делаю:

ringProgress.setProgress(20);

Это означает, что 20% кольца теперь будет заполнено.

То, что я пытаюсь сделать, это оживить кольцо, заполняющееся за несколько секунд. Итак, что я пытался сделать это:

@Override
public void onResume()
{
    super.onResume();
    HandlerThread handlerThread = new HandlerThread("countdown");
    handlerThread.start();
    Handler handler = new Handler(handlerThread.getLooper());
    handler.post(new Runnable()
    {
        @Override
        public void run()
        {
            final Timer timer = new Timer();
            timer.scheduleAtFixedRate(new TimerTask()
            {
                int totalSeconds = secondsToStart + minutesToStart * 60;
                int secondsPassed = 0;

                @Override
                public void run()
                {
                    if(secondsPassed == totalSeconds)
                    {
                        timer.cancel();
                    }
                    final int currentProgress = (secondsPassed / totalSeconds) * 100;
                    secondsPassed++;
                    getActivity().runOnUiThread(new Runnable()
                    {
                        @Override
                        public void run()
                        {
                            mRingProgressBar.setProgress(currentProgress);
                        }
                    });

                }
            }, 0, 1000);

        }
    });
}

Проблема в том, что обновление кольца не отображается, пока не истечет время. Например, если я установлю его на 5 секунд, то при загрузке фрагмента кольцо будет установлено на 0, тогда в течение 5 секунд ничего не произойдет, и тогда кольцо заполнится на 100% сразу.

Как правильно запустить эту анимацию?

4 ответа

Решение

Вместо использования обработчика вы можете использовать аниматор свойств следующим образом:

ObjectAnimator.ofInt(mRingProgressBar, "progress", 0, 100)
    .setDuration(totalSeconds * 1000)   //time is in miliseconds
    .start();

Это найдет метод setProgress() в вашем mRingProgressBarи установите значение в соответствии с данными ограничениями. В приведенном выше примере от 0 до 100. Подробнее об этом можно прочитать здесь.

Я думаю, что проблема с

final int currentProgress = (secondsPassed / totalSeconds) * 100;

secondsPassed / totalSeconds вернуть значение int, так что оно будет 0 или 1. И вы умножаете это до 100.

Вы должны использовать float или же double вместо

что-то вроде

final int currentProgress = Math.round(((float) secondsPassed)/((float) totalSeconds)*100f);

На этой линии:

Handler handler = new Handler(handlerThread.getLooper());

Вы пытаетесь получить петлителя от handlerThread, Но насколько вы уверены, что петлитель уже был инициализирован?

Из документации getLooper()

Этот метод возвращает Looper, связанный с этим потоком. Если этот поток не был запущен или по какой-либо причине isAlive() возвращает false, этот метод возвратит ноль. Если этот поток был запущен, этот метод будет блокироваться, пока петлитель не будет инициализирован.

onLooperPrepared() это обратный вызов, где вы можете быть уверены, что Looper был инициализирован, и поэтому вы можете построить логику на этом.

Таким образом, то, что вы должны сделать, это подкласс HandlerThread и создать соответствующую логику из onLooperPrepared() Перезвоните.

Вот хороший пост, который поможет вам. Смотрите реализацию MyWorkerThread класс там.

Поскольку вы хотите работать в другом потоке, вы можете использовать этот обработчик в верхней части класса:

     private int progress = 0;
     Handler timerHandler = new Handler();
     Runnable timerRunnable = new Runnable() {
            @Override
            public void run() {

            ringProgress.setProgress(progress);
            progress += 20;
            if (progress == 100) { //clear??
            }
            timerHandler.postDelayed(this, 1000);
        }
    };

В inCreate установить максимум:

ringProgress.setMax(100);

Это завершит анимацию в течение 5 секунд, затем вы сможете очистить анимацию. Если вы хотите меньшие приращения, измените строку ниже (обновлять каждую десятую секунды) и измените шаги

timerHandler.postDelayed(this, 100);
Другие вопросы по тегам