线程随着时间的推移变慢

Thread slows down over time

我正在尝试制作彩虹色标题(随时间变化),这是 onCreate:

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

    new Thread(TitleColorRunnable).start();

}

对应的runnable:

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

这个线程随着时间的推移变慢,并开始慢慢地破坏整个 UI,直到一切都完全停止。

是否有可能

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

继续将新的 ForegroundColorSpan 变量保存到内存中?

请帮忙,谢谢!

参考。该行:

title.post(new Runnable()...

无法保证在您下次调用 title.post() 时 Runnable 已完成并已出队。您应用程序 Looper 中的 Runnables 队列可能积压得很厉害。 IOW,你排队 Runnables 的速度快于它们可以执行的速度,最终你的 UI 线程必须花费所有时间来处理这些,而不是做你想让它做的其他事情,比如响应用户输入等等。

一个影响因素是您的 10 毫秒延迟:Thread.sleep(10)。 100Hz 对于这种更新来说有点快; 30Hz 应该足够了(对于人类感知),甚至更慢,因为你只是 几乎 改变颜色。

建议修复

  • 去掉线程。把你的 TitleColorRunnable 逻辑移到 onCreate().
  • 将你的 Runnable——你现在作为闭包的那个——声明为最终局部变量。
  • 在你的 myRunnable.run() 中,执​​行 title.postDelayed( myRunnable, 33 )。这就是诀窍;这就是让迭代继续进行的原因,也是阻止 Looper 队列填满的原因。由于 myRunnable 重新排队 本身 ,队列中永远不会超过一个 myRunnable。 (这不是递归;您只是利用 Android 消息队列机制来安排您的 Runnable。)33 毫秒用于 30Hz 更新率。
  • 要开始整个事情,请将 title.post( myRunnable ) 添加到 onCreate()
  • 改为mainHue = mainHue + 3;,以保持颜色以大致相同的速度变化。

显然,使用此解决方案,您必须更改 myRunnable.run().

mainHue 的状态