在 UI 线程中通信时链接一系列操作

Chaining a sequence of actions when communicating in a UI thread

我正在设计一个小型应用程序,它每秒用一个随机字母更改 TextView

现在,我的代码看起来像这样并且运行良好:

@BindView(R.id.textview_letter) TextView letterTV;
private static final int DELAY_MILLIS = 1000;
private static final int LOOP_MAX = 10;
private static final String ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

private Handler h = new Handler();
private Random random = new Random();
private int position = 0;

private Runnable run = new Runnable() {
    @Override
    public void run() {
        if (position >= LOOP_MAX) {
            letterTV.setText("THE END !");
            h.removeCallbacks(run);
        } else {
            String randomLetter = String.valueOf(ALPHABET.charAt(random.nextInt(ALPHABET.length())));
            letterTV.setText(randomLetter);
            h.postDelayed(run, DELAY_MILLIS);
            position++;
        }
    }
};

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.mylayout);
    ButterKnife.bind(this);
    h.post(run);
}

我现在想通过将 TextView 的背景设置为黑色(或使其不可见)每个字母之间的几毫秒来改进它,以便在出现两次相同字母时通知用户连续。

我唯一的菜鸟想法是在我的 Runnable 中放置另一个 Runnable 并使用拆分延迟处理它们(例如 700 和 300 毫秒),但这似乎过于复杂。

正确的做法是什么?
(顺便说一句,Runnable/Handler 真的是最适合我使用的模式吗?)

编辑:在非UI线程中我可以做这样的事情:

while (randomLetter.next()) {
    letterTV.setText(randomLetter);
    Thread.sleep(700);
    letterTV.setBackgroundColor(Color.BLACK);
    Thread.sleep(300);
}

使用RxAndroid,会降低复杂度:

public class Test extends AppCompatActivity {

    private Disposable randomLetterObservable;
    private TextView textView;
    private Random random = new Random();
    private final String ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        textView = findViewById(R.id.textView);

        randomLetterObservable = Observable.interval(500L, TimeUnit.MILLISECONDS)
                .timeInterval()
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<Timed<Long>>() {
                    @Override
                    public void accept(Timed<Long> longTimed) throws Exception {
                        String randomLetter = String.valueOf(ALPHABET.charAt(random.nextInt(ALPHABET.length())));
                        textView.setText(randomLetter);
                    }
                });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (randomLetterObservable != null) {
            randomLetterObservable.dispose();
        }
    }
}

具有依赖项:

implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
implementation 'io.reactivex.rxjava2:rxjava:2.1.8'

编辑: 这是一个修改后的解决方案,如果同一字母连续出现两次,它也会更改背景。

public class Test extends AppCompatActivity {

    private Disposable randomLetterObservable;
    private TextView textView;
    private Random random = new Random();
    private final String ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    private String lastLetter;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        textView = findViewById(R.id.textView);

        randomLetterObservable = Observable.interval(700L, TimeUnit.MILLISECONDS)
                .timeInterval()
                .observeOn(AndroidSchedulers.mainThread())
                .switchMap(new Function<Timed<Long>, ObservableSource<String>>() {
                    @Override
                    public ObservableSource<String> apply(Timed<Long> longTimed) throws Exception {
                        String randomLetter = String.valueOf(ALPHABET.charAt(random.nextInt(ALPHABET.length())));
                        if (randomLetter.equals(lastLetter)) {
                            textView.setBackgroundColor(Color.BLACK);
                            return Observable.just(randomLetter)
                                    .observeOn(Schedulers.computation())
                                    .debounce(300L, TimeUnit.MILLISECONDS);
                        } else {
                            lastLetter = randomLetter;
                            return Observable.just(randomLetter);
                        }
                    }
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<String>() {
                    @Override
                    public void accept(String s) throws Exception {
                        textView.setText(s);
                        textView.setBackgroundColor(Color.TRANSPARENT);
                    }
                });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (randomLetterObservable != null) {
            randomLetterObservable.dispose();
        }
    }
}

事件在后台线程中发出,背景颜色和字母在主线程中设置。我认为这几乎就是您所要求的。 (您可能需要调整这些值以获得所需的效果)。

祝你好运。