【问题标题】:Periodically updated text is not being displayed不显示定期更新的文本
【发布时间】:2017-01-31 01:49:14
【问题描述】:

我有一个 for 循环,我想在其中调用 setText 方法。除了在脚本完成运行之前文本不会更改的事实之外,这可以正常工作。我想要它做的是每次调用setText 方法时更改代码。我在下面附上了我的代码,它应该非常困难。 代码:

package com.example.zoe.andone;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;

import java.util.concurrent.TimeUnit;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    public void startLoop(View view) {
        String string = getString(R.string.hello);
        ((TextView)findViewById(R.id.hello)).setText("starting...");
        for (int i = 0; i < 10; i++) {
            String updated = Integer.toString(i);
            ((TextView)findViewById(R.id.hello)).setText(updated);
            try {
                Thread.sleep(250);
            } catch(InterruptedException ex) {
                Thread.currentThread().interrupt();
            }
        }
        ((TextView)findViewById(R.id.hello)).setText("done!");
    }
}

【问题讨论】:

  • 使用Handler 而不是在主线程上调用Thread.sleep(250);
  • 我不确定我是否关注。

标签: java android for-loop settext


【解决方案1】:

这就是所谓的“丢帧”。

是时候学习了!

在回答之前,让我们解释一下这里发生了什么。

您可能已经知道 android 的帧速率为 60fps(每秒 60 帧),这意味着屏幕每 1/60 秒渲染一次并显示给用户(以提供最佳清晰度)。它通过每 1/60 秒在您的应用程序(以及其他任何需要渲染的地方)上运行一些渲染代码来计算显示的屏幕在这个特定的毫秒时应该是什么样子(它被称为帧)。

但是,执行此操作的代码在 UI 线程上运行,如果您在渲染滴答开始时执行任何操作,Android 框架只会丢弃该帧(它不会计算它)。 在您的情况下,Thread.sleep(250); 是导致您的帧被丢弃的原因,因为它在您的 for 循环的每次迭代中都将 UI 线程保持 250 毫秒(所以它是 250 毫秒 *(10 - 1),这是很多帧)。

丢帧意味着在 UI 上看不到任何更新。

解决方案

您应该安排更新任务每 250 毫秒运行一次,而不是使用 Thread.sleep(250); 和丢帧。就是这样。

private int i = 0; // Does the trick!
public void startLoop(View view) {
    String string = getString(R.string.hello);
    ((TextView)findViewById(R.id.hello)).setText("starting...");
        final Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                if (i < 10) {
                    String updated = Integer.toString(i);
                    i++;
                    updateHelloOnUiThread(updated);
                } else {
                    updateHelloOnUiThread("done!");
                    handler.removeCallbacksAndMessages(null);
                    i = 0; // For future usages
                }
            }
        },250);
}

private void updateHelloOnUiThread(final String text) {
     MainActivity.this.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                ((TextView)findViewById(R.id.hello)).setText(text);
            }
     });
}

进一步阅读

Android UI : Fixing skipped frames

High Performance Android Apps, Chapter 4. Screen and UI Performance

【讨论】:

  • 我正在使用你的代码,但是它给了我一个错误说Variable 'handler' initializer 'new Handler().postDelayed(new Runnable() { @Override public void run() { ...' is redundant我不知道如何解决这个问题:(
  • 当我将鼠标悬停在它上面时会发生这种情况。当我尝试构建它时出现的错误是Error:(28, 21) error: cannot assign a value to final variable i 谢谢!
  • 酷,再次感谢您的帮助。它抱怨我没有将i 传递给函数有什么想法吗?
  • 晚饭!它工作(ish)它编译得很好,但它不会每次都输出不同的数字,它只是保持为零:(
  • 另一个更新(移动 i 成为您活动的私有属性)
【解决方案2】:
this.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                int globalTimer = 0;

                int limitTimer = 10;
                int i = 0;

                // create Timer
                Timer timer = new Timer();
                timer.schedule(new TimerTask() {
                    @Override
                    public void run() {
                        globalTimer++;
                        //run your code
                        ((TextView)findViewById(R.id.hello)).setText(i+"");
                        i++;
                        //check if globalTimer is equal to limitTimer
                        if (globalTimer == limitTimer) {
                            timer.cancel(); // cancel the Timer
                        }
                    }

                }, 0, 250);
            }
        });

【讨论】:

    【解决方案3】:

    问题是,您在 UI 线程上调用 Thread.sleep。 如果线程处于休眠状态,则无法更新 UI(屏幕上显示的内容)。

    【讨论】:

      猜你喜欢
      • 2018-06-18
      • 1970-01-01
      • 2017-06-26
      • 1970-01-01
      • 2013-03-07
      • 2014-06-05
      • 1970-01-01
      • 2012-09-04
      • 2020-12-26
      相关资源
      最近更新 更多