Как переключаться между цветами фона в Android/Java?

У меня есть список шестнадцатеричных цветов с продолжительностью в миллисекундах для каждого из них. Я хотел бы заполнить экран каждым цветом в течение его продолжительности, а затем перейти к следующему цвету.

Я попытался перебрать цвета, чтобы сделать следующее:

 myView.setBackgroundColor(Color.parseColor( theColor ));
 SystemClock.sleep( theDuration );

 myView.setBackgroundColor(Color.parseColor( nextColor ));
 SystemClock.sleep( nextDuration );

 etc...

что казалось мне очевидным, но ничего не делает с представлением, когда оно работает, по крайней мере, в моем AVD. Я узнаю, что это потому, что Android рисует только в заранее определенное время. (Я также безуспешно пытался вызвать «Invalidate()».)

Каков наилучший способ отображения всех цветов последовательно?

(Я понимаю, что мне также не следует вызывать sleep(), поэтому любые предложения по этому поводу также будут оценены.)

Спасибо.


person ScottyB    schedule 04.02.2014    source источник
comment
Есть ли шанс, что вы могли бы опубликовать больше кода в этом классе/активности? Было бы полезно посмотреть, в каком это методе или с чем еще он взаимодействует.   -  person Alex Vulaj    schedule 05.02.2014


Ответы (3)


new Thread() {
    @Override
    public void run() {
        YourActivity.this.runOnUiThread(new Runnable() {
        @Override
        public void run() {
            myView.setBackgroundColor(Color.parseColor( theColor ));
        }
        Thread.sleep( theDuration);

        YourActivity.this.runOnUiThread(new Runnable() {
        @Override
        public void run() {
            myView.setBackgroundColor(Color.parseColor( nextColor ));
        }
        Thread.sleep( nextDuration );
    }
}.start();

Поместите это в метод и вызовите его.

person Community    schedule 05.02.2014
comment
(Мой предыдущий комментарий был опубликован преждевременно...) В итоге я создал Runnable внутри обработчика событий нажатия кнопки. Все (перебор цветов и длительности плюс сон в зависимости от длительности) выполняется в Runnable. Затем я создал обработчик внутри своего класса активности пользовательского интерфейса, который просто меняет цвет фона. Runnable отправляет обработчику сообщение, содержащее цвет фона, используя объекты Bundle/Message. - person ScottyB; 05.02.2014

Есть много способов добиться желаемого. Можно было бы использовать Handler и Runnable. Предполагая, что вы знаете, как получить текущий цвет и продолжительность, вы можете сделать:

  • объявить Runnable как переменную класса

    private Runnable runnable = null;
    
  • внутри onCreate(), после того, как вы установите начальный вид, инициализируйте обработчик

    final Handler handler = new Handler();
    
  • инициализировать runnable и изменить фон в методе run()

    runnable = new Runnable() {
        @Override
        public void run() {
            //change the color
            myView.setBackgroundColor(currentColor);
    
            //run it again in nextDuration miliseconds
            handler.postDelayed(toggle, nextDuration);
        }
    };
    
    //start runnable in theDuration miliseconds
    handler.postDelayed(toggle, theDuration);
    

Вы можете иметь массивы цветов и длительностей и циклически перемещаться по ним с помощью индексной переменной. Это предполагает, что myView является допустимым представлением.

ИЗМЕНИТЬ:

Тем, кто проголосовал против, прочтите документацию по Handler:

Когда вы создаете новый обработчик, он привязывается к потоку/очереди сообщений потока, который его создает...

Другими словами, вы создаете обработчик в onCreate() своей активности, чтобы он мог обновлять ваше представление.

В этом сообщении блога с веб-сайта разработчиков Android используется очень похожая конструкция, предложенная выше.

Обработчик запускает код обновления как часть вашего основного потока, избегая накладных расходов на второй поток, а также упрощая доступ к иерархии представлений, используемой для пользовательского интерфейса.

См. здесь и здесь ответил CommonsWare и здесь – ответил Лейт Альнагем.

person Melquiades    schedule 04.02.2014
comment
Я понял, что Runnables не могут работать в потоке пользовательского интерфейса, поэтому они не могут изменять объекты View. Разве не нужно отправлять сообщение в поток пользовательского интерфейса, чтобы сообщить ему об обновлении цвета фона? - person ScottyB; 05.02.2014
comment
@ScottBowers, пожалуйста, проверьте обновленный ответ. Даунвотеру - объясните почему. - person Melquiades; 05.02.2014
comment
Я не понизил его, так как я новичок в программировании на Android/Java и все еще учусь. Спасибо за объяснение. Но поскольку обработчик является частью потока пользовательского интерфейса, не будет ли он блокировать пользовательский интерфейс на время его действия и (возможно) заставлять Android отображать предупреждение пользователю? - person ScottyB; 05.02.2014
comment
Как говорится в блоге Android: Просто помните, что такие задачи должны быть небольшими и легкими, чтобы не замедлять работу пользователя, и вы просто меняете цвет фона, так что все должно быть в порядке. Проверьте ссылки, если у вас все еще есть сомнения. - person Melquiades; 05.02.2014

В итоге я создал Runnable внутри обработчика событий нажатия кнопки. Все (перебор цветов и длительности, а также «засыпание» в зависимости от длительности) выполняется в методе Runnable run().

public void playOnClick(View v) {
    Runnable runnable = new Runnable() {
        public void run() {
            ...
        }

Затем я создал обработчик внутри своего класса активности пользовательского интерфейса, который просто меняет цвет фона.

Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        Bundle b = msg.getData();
        String theColor = b.getString("color");

        myView = (View) findViewById(R.id.bigView);
        myView.setBackgroundColor(Color.parseColor(theColor));
    }
};

Внутри метода run() он Runnable отправляет обработчику сообщение, содержащее цвет фона, используя объекты Bundle/Message:

b = new Bundle();
b.putString("color", theColor);
msg = new Message();
msg.setData(b);
handler.sendMessage(msg);
person ScottyB    schedule 05.02.2014