不显示定期更新的文本
Periodically updated text is not being displayed
我有一个 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!");
}
}
这就是所谓的"dropping frames"。
是时候学习了!
在回答之前,让我们解释一下这里发生了什么。
您可能已经知道 android 的 frame-rate 为 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
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);
}
});
问题是,您在 UI 线程上调用 Thread.sleep。
如果线程正在休眠,它无法更新 UI(屏幕上显示的内容)。
我有一个 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!");
}
}
这就是所谓的"dropping frames"。
是时候学习了!
在回答之前,让我们解释一下这里发生了什么。
您可能已经知道 android 的 frame-rate 为 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
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);
}
});
问题是,您在 UI 线程上调用 Thread.sleep。 如果线程正在休眠,它无法更新 UI(屏幕上显示的内容)。