Предотвращение "мерцания" при вызове Drawable.draw () - PullRequest
3 голосов
/ 13 февраля 2011

У меня есть небольшое приложение для экспериментов (по существу, очень урезанная версия LunarLander в Android SDK) с одним SurfaceView. У меня есть Drawable «спрайт», который я периодически рисую в SurfaceView Canvas объекте в разных местах, не пытаясь стереть предыдущее изображение. Таким образом:

private class MyThread extends Thread {
    SurfaceHolder holder;  // Initialised in ctor (acquired via getHolder())
    Drawable      sprite;  // Initialised in ctor
    Rect          bounds;  // Initialised in ctor

    ...

    @Override
    public void run() {
        while (true) {
            Canvas c = holder.lockCanvas();
            synchronized (bounds) {
                sprite.setBounds(bounds);
            }
            sprite.draw(c);
            holder.unlockCanvasAndPost(c);
        }
    }

    /**
     * Periodically called from activity thread
     */
    public void updatePos(int dx, int dy) {
        synchronized (bounds) {
            bounds.offset(dx, dy);
        }
    }
}

При запуске в эмуляторе я вижу, что после нескольких обновлений несколько старых «копий» изображения начинают мерцать, то есть появляются и исчезают. Сначала я предположил, что, возможно, я неправильно понял семантику Canvas, и что она каким-то образом поддерживает «слои», и что я избил его до смерти. Однако потом я обнаружил, что этот эффект появляется только в том случае, если я пытаюсь обновляться быстрее, чем примерно каждые 200 мс. Так что моя следующая лучшая теория заключается в том, что это, возможно, артефакт эмулятора, который не в состоянии поспеть и порвать дисплей. (У меня пока нет физического устройства для тестирования.)

Является ли любая из этих теорий правильной?

Примечание. На самом деле я не хочу делать это на практике (то есть рисовать сотни наложенных копий одного и того же). Однако я хотел бы понять, почему это происходит.

Окружающая среда:

  • Eclipse 3.6.1 (Helios) в Windows 7
  • JDK 6
  • Android SDK Tools r9
  • Приложение нацелено на Android 2.3.1

Тангенциальный вопрос:

Мой метод run() по сути является упрощенной версией того, как работает пример LunarLander (со всей лишней логикой). Я не совсем понимаю, почему это не приведет к насыщению процессора, так как, похоже, ничто не мешает ему работать на полную мощность. Кто-нибудь может уточнить это?

Ответы [ 2 ]

12 голосов
/ 17 февраля 2011

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

Когда вы рисуете что-либо на Canvas, прикрепленном к Surface, вы рисуете в «обратный» буфер (невидимый).И когда вы unlockCanvasAndPost() переставляете буферы поверх ... то, что вы нарисовали, внезапно становится видимым, когда «задний» буфер становится «передним», и наоборот.Итак, ваш следующий кадр рисования выполняется в старом «переднем» буфере ...

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

Поняв это, я думаю, что реальный вопрос заключается в том, почему он не мигаетаппаратное обеспечение?Поработав над графическими драйверами в прошлые годы, я могу догадываться о причинах, но стесняюсь рассуждать слишком далеко.Надеюсь, что выше будет достаточно, чтобы удовлетворить ваши любопытство об этом артефакте рендеринга.: -)

1 голос
/ 18 февраля 2011

Вам необходимо очистить предыдущую позицию спрайта, а также новую позицию.Это то, что система View делает автоматически.Однако, если вы используете поверхность напрямую и не перерисовываете каждый пиксель (либо непрозрачным цветом, либо в режиме смешивания SRC), вы должны очистить содержимое буфера самостоятельно.Обратите внимание, что вы можете передать грязный прямоугольник в lockCanvas (), и он выполнит объединение для вас предыдущего грязного прямоугольника и того, который вы передаете (это механизм, используемый инструментарием пользовательского интерфейса.) Он также установит прямоугольник клипа.Canvas - объединение этих двух прямоугольников.

Что касается вашего второго вопроса, unlockAndPost () выполнит vsync, поэтому вы никогда не будете рисовать со скоростью более ~ 60 кадров в секунду (большинство устройств, которые я виделустановите частоту обновления дисплея около 55 Гц.)

...