我有以下类(class)。该类(class)的目的是让我通过每秒显示大约十个字符来模拟电传打字机/打字机。
CharacterLoopThread 类的要点是查看 outputBuffer,如果其中有任何字符,则在 UI 线程上调用一个 runnable 来提取第一个字符并将其放入 textView。然后线程 hibernate 大约 100 毫秒。 (这里有一些恶作剧……虽然我在 1979 年使用电传打字机时非常棒,但现在对我来说有点慢了。所以每 10 个字符,我稍微减少延迟。当没有更多字符可显示时,我将延迟重置为 100 毫秒...)
我删除了类(class)的底部,因为它与我的问题无关。
我这里的东西似乎运作良好。但是,它是因为我还是不顾我而起作用?您首选的编写线程和处理程序的方式是什么?
public class MyActivity extends Activity {
private TextView textView;
private ScrollView scrollView;
private StringBuilder outputBuffer;
private Handler handler;
private CharacterLooperThread characterLooperThread;
(剪断)
private class CharacterLooperThread extends Thread {
private boolean allowRun;
private Runnable run;
int effectiveCharacterDelay;
int characterCount;
public CharacterLooperThread() {
allowRun = true;
run = new Runnable() {
public void run() {
/**
* Don't do anything if the string has been consumed. This is necessary since when the delay
* is very small it is possible for a runnable to be queued before the previous runnable has
* consumed the final character from the outputBuffer. The 2nd runnable will cause an
* exception on the substring() below.
*/
if (outputBuffer.length() == 0) return;
try {
textView.append(outputBuffer.substring(0, 1));
scrollToBottom();
outputBuffer.deleteCharAt(0);
} catch (Exception e) {
toast(getMsg(e));
}
}
};
}
public void run() {
resetDelay();
while (allowRun) {
/**
* This if() performs 2 functions:
* 1. It prevents us from queuing useless runnables in the handler. Why use the resources if
* there's nothing to display?
* 2. It allows us to reset the delay values. If the outputBuffer is depleted we can reset the
* delay to the starting value.
*/
if (outputBuffer.length() > 0) {
handler.post(run);
reduceDelay();
} else {
resetDelay();
}
try {
Thread.sleep(effectiveCharacterDelay);
} catch (InterruptedException e) {
toast("sleep() failed with " + e.getMessage());
}
}
/**
* Make sure there's no runnable on the queue when the thread exits.
*/
handler.removeCallbacks(run);
}
public void exit() {
allowRun = false;
}
最佳答案
一个想法是使用 Handler.postDelayed
来安排单独的“击键”。您可以一次完成所有这些操作,也可以让每次击键 Runnable
在完成时安排下一次击键;如果处理进度落后,前一种方法将尽快 catch ,而后者基本上会将所有内容推回以保持相同的击键间延迟。
看到一个线程更改 StringBuilder
而另一个线程读取它让我很担心。 (StringBuilder
类是 StringBuffer
的非线程安全后继类,它是在人们认为使单个类线程安全是好的设计的那一天写的)。如果它不偶尔做一些意想不到的事情,那么你很幸运,尽管这里不会出错。但是,使用 postDelayed
,您可能会完全摆脱后台线程。
只要您创建匿名 Runnable
类,请注意您可以为它们提供参数(只要您声明变量 final
)。所以我倾向于一次向每个 Runnable
发送一个字符,如下所示:
long delay = 0;
for (int j = 0; j < outputBuffer.length(); ++j) {
final CharSequence s = outputBuffer.subSequence(j, j + 1);
handler.postDelayed(new Runnable() {
@Override public void run() {
textView.append(s);
scrollToBottom();
}
}, delay);
delay += 100; // or whatever
}
关于java - android 线程和处理程序最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10150093/