TimerTask.run() 中的命令执行顺序错误(在 Android 中编写的应用程序 Java)
Wrong order of commands execution in TimerTask.run() (in Android app written in Java)
我正在编写一个简单的 android 应用程序(在 Java 中),它应该能够加载 *.txt 文件并每 0.5 秒一次显示一个单词的内容。我设法将一个文本文件的内容放入一个字符串数组中,该数组在每个索引下存储一个单词。我正在使用 Timer 和 TimerTask 以给定的时间间隔在 TextView 中显示数组中的单词。为了实现这个目标,我的 TimerTask 运行() 方法首先调用 TextViev.setText() 方法,该方法在当前索引处显示数组中的项目,然后递增索引(或者我认为如此)。事实证明,索引首先递增,然后 TextViev.setText() 方法被调用(尽管 TimerTask 的重写 运行() 方法中的命令顺序)。我的问题是:为什么命令按这个顺序执行,我该如何解决?
TimerTask readingTimerTask = new TimerTask() {
@Override
public void run() {
if (wordIndex < textArr.length - 1) {
runOnUiThread(new Runnable() {
@Override
public void run() {
tvWords.setText(textArr[wordIndex]);
Log.i(LOG_TAG, "setText() called. wordIndex: " + String.valueOf(wordIndex));
}
});
wordIndex++;
Log.i(LOG_TAG, "wordIndex incremented. New value of wordIndex: " + String.valueOf(wordIndex));
} else {
stopReading();
}
}
};
mTimer = new Timer();
Log.i(LOG_TAG, "Timer is starting. wordIndex: " + String.valueOf(wordIndex));
mTimer.schedule(readingTimerTask, 100, displayTimeInMs);
Logcat 看起来像这样:
D/MainActivity: wordIndex in onActivityResult (file loaded): 0
I/MainActivity: Timer is starting. wordIndex: 0
I/MainActivity: wordIndex incremented. New value of wordIndex: 1
I/MainActivity: setText() called. wordIndex: 1
I/MainActivity: wordIndex incremented. New value of wordIndex: 2
I/MainActivity: setText() called. wordIndex: 2
I/MainActivity: wordIndex incremented. New value of wordIndex: 3
I/MainActivity: setText() called. wordIndex: 3
I/MainActivity: wordIndex incremented. New value of wordIndex: 4
I/MainActivity: setText() called. wordIndex: 4
I/MainActivity: wordIndex incremented. New value of wordIndex: 5
I/MainActivity: setText() called. wordIndex: 5
I/MainActivity: Timer has been stopped. wordIndex: 5
为什么命令按这个顺序执行?
从后台线程调用时,runOnUiThread()
不会等待 run()
中的命令完成后再返回。它安排它们在 单独的线程 上执行:UI 线程。
我假设您的代码片段是在 UI(或“主”)线程上调用的。同时,您的 TimerTask
引入了第二个线程:它的内部后台工作者。 IOW,你已经创建了一个 race condition.
wordIndex++
保证首先执行,在这种情况下,但它通常会“赢得”比赛,因为它需要一点时间UI 线程处理 Runnable
.
我该如何解决?
您可能不打算在您的程序中引入多线程——这会使事情变得相当复杂,而且不适合新手程序员。您可能想要使用 CountDownTimer
,而不是 TimerTask
。这将帮助您将所有内容都放在 UI 线程上。
我正在编写一个简单的 android 应用程序(在 Java 中),它应该能够加载 *.txt 文件并每 0.5 秒一次显示一个单词的内容。我设法将一个文本文件的内容放入一个字符串数组中,该数组在每个索引下存储一个单词。我正在使用 Timer 和 TimerTask 以给定的时间间隔在 TextView 中显示数组中的单词。为了实现这个目标,我的 TimerTask 运行() 方法首先调用 TextViev.setText() 方法,该方法在当前索引处显示数组中的项目,然后递增索引(或者我认为如此)。事实证明,索引首先递增,然后 TextViev.setText() 方法被调用(尽管 TimerTask 的重写 运行() 方法中的命令顺序)。我的问题是:为什么命令按这个顺序执行,我该如何解决?
TimerTask readingTimerTask = new TimerTask() {
@Override
public void run() {
if (wordIndex < textArr.length - 1) {
runOnUiThread(new Runnable() {
@Override
public void run() {
tvWords.setText(textArr[wordIndex]);
Log.i(LOG_TAG, "setText() called. wordIndex: " + String.valueOf(wordIndex));
}
});
wordIndex++;
Log.i(LOG_TAG, "wordIndex incremented. New value of wordIndex: " + String.valueOf(wordIndex));
} else {
stopReading();
}
}
};
mTimer = new Timer();
Log.i(LOG_TAG, "Timer is starting. wordIndex: " + String.valueOf(wordIndex));
mTimer.schedule(readingTimerTask, 100, displayTimeInMs);
Logcat 看起来像这样:
D/MainActivity: wordIndex in onActivityResult (file loaded): 0
I/MainActivity: Timer is starting. wordIndex: 0
I/MainActivity: wordIndex incremented. New value of wordIndex: 1
I/MainActivity: setText() called. wordIndex: 1
I/MainActivity: wordIndex incremented. New value of wordIndex: 2
I/MainActivity: setText() called. wordIndex: 2
I/MainActivity: wordIndex incremented. New value of wordIndex: 3
I/MainActivity: setText() called. wordIndex: 3
I/MainActivity: wordIndex incremented. New value of wordIndex: 4
I/MainActivity: setText() called. wordIndex: 4
I/MainActivity: wordIndex incremented. New value of wordIndex: 5
I/MainActivity: setText() called. wordIndex: 5
I/MainActivity: Timer has been stopped. wordIndex: 5
为什么命令按这个顺序执行?
从后台线程调用时,runOnUiThread()
不会等待 run()
中的命令完成后再返回。它安排它们在 单独的线程 上执行:UI 线程。
我假设您的代码片段是在 UI(或“主”)线程上调用的。同时,您的 TimerTask
引入了第二个线程:它的内部后台工作者。 IOW,你已经创建了一个 race condition.
wordIndex++
保证首先执行,在这种情况下,但它通常会“赢得”比赛,因为它需要一点时间UI 线程处理 Runnable
.
我该如何解决?
您可能不打算在您的程序中引入多线程——这会使事情变得相当复杂,而且不适合新手程序员。您可能想要使用 CountDownTimer
,而不是 TimerTask
。这将帮助您将所有内容都放在 UI 线程上。