Поток замедляется со временем - PullRequest
0 голосов
/ 08 сентября 2018

Я пытаюсь сделать заголовок цвета радуги (который меняется со временем), вот onCreate:

protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_menu);

    new Thread(TitleColorRunnable).start();

}

И соответствующий ему запуск:

Runnable TitleColorRunnable = new Runnable()
{
    TextView title;
    int titleLength;
    Spannable spannable;
    int i;
    float mainHue = 15;
    float hue;
    int color;

    @Override
    public void run()
    {
        title = findViewById(R.id.titleTextView);
        title.setText("TITLE EXAMPLE", TextView.BufferType.SPANNABLE);
        titleLength = title.length();
        spannable = (Spannable) title.getText();

        while (true)
        {
            for (i = 0; i < titleLength - 1; i++)
            {
                hue = (mainHue - i) % 360;
                color = Color.HSVToColor(new float[]{hue, 1, 1});

                title.post(new Runnable()
                {
                    @Override
                    public void run()
                    {
                        spannable.setSpan(new ForegroundColorSpan(color), i, i + 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                    }
                });
            }

            mainHue++;
            if (mainHue == 360)
            {
                mainHue = 0;
            }

            try
            {
                Thread.sleep(10);
            } catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }
    }
};

Этот поток замедляется с течением времени и начинает медленно глючить весь пользовательский интерфейс, пока все полностью не остановится.

Возможно ли, что линия

spannable.setSpan(new ForegroundColorSpan(color), i, i + 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

продолжать сохранять новые переменные ForegroundColorSpan в памяти?

Пожалуйста, помогите, спасибо!

1 Ответ

0 голосов
/ 11 сентября 2018

Ref. строка:

title.post(new Runnable()...

Ничто не может гарантировать, что Runnable завершится и будет снят с обслуживания к тому времени, когда вы в следующий раз позвоните title.post(). Очередь Runnables внутри Looper вашего приложения, вероятно, перегружена. IOW, вы ставите в очередь Runnable быстрее, чем они могут быть выполнены, и в конечном итоге ваш поток пользовательского интерфейса должен тратить все свое время, занимаясь этим, вместо того, чтобы делать другие вещи, которые вы хотели бы сделать, такие как реагирование на ввод пользователя и и пр.

Способствующим фактором является ваша задержка в 10 мс: Thread.sleep(10). 100 Гц немного быстр для такого рода обновления; 30 Гц должно быть достаточно (для человеческого восприятия) или даже медленнее, поскольку вы просто едва меняете цвет.

Предлагаемое исправление

  • Избавься от темы. Возьмите свою TitleColorRunnable логику и переместите ее на onCreate().
  • Объявите свой Runnable - тот, который у вас есть, как закрытие - в качестве конечной локальной переменной.
  • Внутри вашего myRunnable.run() выполните title.postDelayed( myRunnable, 33 ). Это хитрость; это то, что поддерживает итерацию, и это предотвращает заполнение очереди Looper. Поскольку myRunnable повторно ставит в очередь само по себе , в очереди никогда не бывает более одного myRunnable. (Это не рекурсия; вы просто используете механизм очереди сообщений Android для планирования своего Runnable.) 33 мс для частоты обновления 30 Гц.
  • Чтобы начать все это, добавьте title.post( myRunnable ) к onCreate().
  • сделайте mainHue = mainHue + 3; вместо этого, чтобы цвет менялся примерно с той же скоростью.

Очевидно, что с этим решением вы должны изменить состояние mainHue внутри myRunnable.run().

...