简体   繁体   English

Java Android,如何在一定时间内动态改变一个TextView的背景色

[英]Java Android, how to dynamically change a TextView background color for certain time

I have a List that consists of a boolean and an int.我有一个由 boolean 和一个 int 组成的列表。 I want to dynamically change the background color between black and white of a TextView for a certain time of (int) numbers.我想在特定时间的(int)数字中动态更改 TextView 的黑色和白色之间的背景颜色。 I have treid this approach so far, however, when running the UI sleeps and the textView will only be updated once at the end.到目前为止,我已经尝试过这种方法,但是,当运行 UI 睡眠时,textView 最后只会更新一次。

       List<Primitive> codeContainer;
       codeContainer.add(new Primitive(3, true));
       codeContainer.add(new Primitive(1, false));
       codeContainer.add(new Primitive(7, true));
       theBlinker = findViewById(R.id.theBlinker);
       theBlinker.setBackgroundColor(ContextCompat.getColor(this, R.color.black));
       submit = findViewById(R.id.submit);

       submit.setOnClickListener(view -> {
           for (Primitive item : codeContainer) {
               blinking(item.getSignalLengthInDits() * 500);
           }
           theBlinker.setBackgroundColor(ContextCompat.getColor(MainActivity.this, R.color.black));
       });
}
   private void blinking(int time) {
       final Handler handler = new Handler();
       new Thread(() -> handler.post(() -> {
          theBlinker = findViewById(R.id.theBlinker);
           ColorDrawable buttonColor = (ColorDrawable) txt.getBackground();
           if (buttonColor.getColor() == Color.BLACK) {
               txt.setBackgroundColor(ContextCompat.getColor(MainActivity.this, R.color.white));
           } else {
               txt.setBackgroundColor(ContextCompat.getColor(MainActivity.this, R.color.black));
           }
           try {
               Thread.sleep(time);
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
       })).start();
   }

Any Ideas?有任何想法吗?

I think you should use executors with handlers.我认为您应该将执行程序与处理程序一起使用。

    //define executors and handlers
    static Executor mExecutor = Executors.newSingleThreadExecutor();
    final static Handler handler = new Handler(Looper.getMainLooper());

       List<Primitive> codeContainer;
       codeContainer.add(new Primitive(3, true));
       codeContainer.add(new Primitive(1, false));
       codeContainer.add(new Primitive(7, true));
       theBlinker = findViewById(R.id.theBlinker);
       theBlinker.setBackgroundColor(ContextCompat.getColor(this, R.color.black));
       submit = findViewById(R.id.submit);

       submit.setOnClickListener(v ->{
          //execute the task
           mExecutor.execute(() ->{
               for (Primitive item : codeContainer) {
                   blinking();

                   //after changing color sleeps the thread
                  try {
                    Thread.sleep(item.getSignalLengthInDits() * 500);
                  } catch (InterruptedException e) {
                    e.printStackTrace();
                  }
               }
               theBlinker.setBackgroundColor(ContextCompat.getColor(MainActivity.this, R.color.black));
           });
       });
}
    private void blinking() {

       //change text view color on the main thread
        handler.post(() -> {
            theBlinker = findViewById(R.id.theBlinker);
            ColorDrawable buttonColor = (ColorDrawable) txt.getBackground();
            if (buttonColor.getColor() == Color.BLACK) {
                txt.setBackgroundColor(ContextCompat.getColor(MainActivity.this, R.color.white));
            } else {
                txt.setBackgroundColor(ContextCompat.getColor(MainActivity.this, R.color.black));
            }
        });
    }


The problem is that you make the UI thread going to sleep.问题是您让 UI 线程进入休眠状态。 You should never ever do that!你永远不应该那样做!

This pauses the entire UI thread and therefore prevent it from doing anything (drawing, changing colors, input detection etc.).这会暂停整个 UI 线程,从而阻止它执行任何操作(绘制、更改 colors、输入检测等)。

There are several better ways to achieve what you want than with using Thread.Sleep (actually you need that almost never with android).有几种比使用Thread.Sleep更好的方法来实现你想要的(实际上你几乎不需要使用 android)。

  1. You only schedule the first change with new Handler().post(..) and from there schedule the next change with new Handler().postDelayed(..) (calling your method "recursively")您只需使用new Handler().post(..)安排第一次更改,然后使用new Handler().postDelayed(..)安排下一次更改(“递归”调用您的方法)
  2. You schedule all the changes instantly with new Handler().postDelayed(..) , but for every new state, you add the delays of the previous ones (add a variable to your loop, that you increment with the current delay and use the sum for every next schedule).您可以使用new Handler().postDelayed(..)立即安排所有更改,但是对于每个新的 state,您添加之前的延迟(向循环添加一个变量,您随着当前延迟递增并使用每个下一个时间表的总和)。
  3. If possible, you can use an animation with the keyframes set to your delay: read this article如果可能,您可以使用 animation 并将关键帧设置为您的延迟: 阅读这篇文章

There are of course more possibilities, but I think for your example these are suitable.当然还有更多的可能性,但我认为对于你的例子来说这些都是合适的。

Btw.顺便提一句。 you don't need an extra thread, as it does nothing than scheduling a task on the UI thread and then die.您不需要额外的线程,因为它只是在 UI 线程上安排任务然后死掉。 new Handler().post(..) makes your task beeing executed after your current code is finished (and possibly other tasks, as it's added to the end of the internal task list). new Handler().post(..)使您的任务在当前代码完成后执行(可能还有其他任务,因为它已添加到内部任务列表的末尾)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM