2

私は次のクラスを持っています。このクラスの目的は、1 秒間に約 10 文字を表示することにより、テレタイプ/タイプライターをシミュレートできるようにすることです。

CharacterLoopThread クラスのポイントは、outputBuffer を確認することです。その中に文字がある場合は、UI スレッドで runnable を呼び出して、最初の文字を取り出して textView に挿入します。その後、スレッドは約 100 ミリ秒スリープします。(ここにはいくつかの悪ふざけがあります... 1979年にテレタイプを使用したときは素晴らしかったですが、今は私の好みでは少し遅いです.遅延を 100ms にリセットします...)

私の質問とは関係がなかったので、クラスの一番下を編集しました。

私がここに持っているものはうまくいくようです。しかし、それは私のために、または私にもかかわらず機能しますか? スレッドとハンドラーを作成する際に、どのような方法をお勧めしますか?

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;
        }
4

1 に答える 1

1

1つのアイデアはHandler.postDelayed、個々の「キーストローク」をスケジュールするために使用することです。これを一度に実行することも、各キーストロークがRunnable終了したときに次のスケジュールを設定することもできます。処理がスケジュールより遅れた場合、前者のアプローチは可能な限り迅速に追いつきますが、後者は基本的にすべてを押し戻して同じキーストローク間の遅延を維持します。

StringBuilderあるスレッドが変更しているのを見て、別のスレッドがそれを読んでいるのを見るのは心配です。(このStringBuilderクラスは、スレッドセーフではない後継StringBufferであり、個々のクラスをスレッドセーフにすることは優れた設計であると人々が考えていた日に書き戻されました)。たまに予期しないことが起こらなければ、幸運ですが、ここでうまくいかないことはあまりありません。ただし、を使用するpostDelayedと、バックグラウンドスレッドを完全に取り除くことができます。

匿名Runnableクラスを作成している限り、引数をフィードできることに注意してください(変数を宣言している限りfinal)。Runnableしたがって、次のように、一度に1文字ずつ投稿する傾向があります。

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
}
于 2012-04-20T00:42:22.640 に答える