Я аннулирую весь экран при каждом звонке?

Я новичок в разработке Android и читаю книгу Hello Android. В нем используется пример судоку, и я имею в виду код здесь

В этом, onTouchScreen, он вызывает метод выбора, который дважды вызывает аннулирование. Вопрос в том, что на invalidating сразу после этого вызывается метод onDraw? Так будет и в этом случае, внутри моего метода выбора это будет делать

  1. аннулировать
  2. вызовите рисование
  3. Сделай что-нибудь
  4. аннулировать
  5. вызовите рисование

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

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

Что именно он пытается сказать здесь?

Добавлена ​​информация

Некоторые логи я добавил в метод onDraw, некоторые при запуске, некоторые в цикле for. Всякий раз, когда я касался нового прямоугольника, вызывались все журналы. Разве это не означает, что весь экран повторно заполняется, так как весь код в onDraw выполняется повторно?


person Kraken    schedule 09.01.2014    source источник


Ответы (5)


Кракен

Q: А как насчет журналов, ведь если мои циклы выполняются, это означает, что весь canvas.draw тоже будет выполняться?
A: Да, весь рисунок будет выполняться в вашем примере кода. Вы должны оптимизировать процесс рендеринга самостоятельно, в методе onDraw.

В: Как система узнает, какой фрагмент кода будет "только" перерисовывать грязную область?
О: Canvas::getClipBounds даст вам грязный прямоугольник, на котором вы должны что-то нарисовать.
Внутри вашего for loop в onDraw, сравните грязный прямоугольник с прямоугольником, который вы хотите нарисовать. Затем сделайте continue, если они не пересекаются.

Но помните, что если у вас есть несколько грязных областей, возвращаемый прямоугольник будет объединением всех грязных областей.
См. следующие два вопроса ниже:
Получение грязной области внутри draw()
Android: сделать недействительным(грязным)

Надеюсь, что это поможет вам.

==========================

Автор прав. Но это еще можно оптимизировать.

Вызов invalidate(Rect) автоматически установит область отсечения для холста. (Вот почему canvas.getClipBounds() может возвращать эту область).
Затем, во время onDraw(), все, что рисуется за пределами области отсечения, будет игнорироваться. Они не отображаются на экране, поэтому ДЕЙСТВИТЕЛЬНО сокращают время рисования.
Но их игнорирование по-прежнему требует накладных расходов. Таким образом, для приложения с интенсивным использованием графики onDraw() может быть лучше оптимизировано, если вы исключите их заранее.

Вы можете найти отличный пример оптимизации onDraw() в Android KeyboardView, который обеспечивает представление метода ввода вашего Android. http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/1.5_r4/android/inputmethodservice/KeyboardView.java

person Zhenghong Wang    schedule 15.01.2014
comment
@ZhenghonghWang Я не уверен, правильно ли я понял, я установил что-то грязное, и в моем коде, в методе onDraw, я на самом деле не получаю явно грязную часть. так вы говорите, что в моем случае все это будет визуализировано? Потому что, по словам автора, он сделал это оптимальным образом, и это будет рендеринг только грязной части. - person Kraken; 16.01.2014
comment
Да, автор, которого вы упомянули, прав. Но процесс рисования можно оптимизировать лучше. Я обновил свой ответ. - person Zhenghong Wang; 16.01.2014
comment
Invalidate with rect не изменяет границы клипа холста при включенном аппаратном ускорении. Весь вид всегда перерисовывается независимо от прямоугольника, переданного в Invalidate. - person jjxtra; 02.10.2015

Это прямо из см. документацию:

Рисование осуществляется путем обхода дерева и рендеринга каждого представления, пересекающего недопустимую область. Поскольку дерево просматривается по порядку, это означает, что родители будут рисовать перед (то есть позади) своих детей, а братья и сестры будут рисоваться в том порядке, в котором они появляются в дереве. Если вы установите фон, который можно рисовать для представления, то представление нарисует его для вас, прежде чем вернуться к своему методу onDraw().

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

Насколько я понимаю, после того, как ваш вид будет нарисован в первый раз, дерево будет сформировано из родительских и дочерних объектов вместе с их позициями на экране. Когда вы передаете назначенную область для признания ее недействительной, это дерево проверяется на наличие затронутых узлов в этой области, и только эти узлы будут вызываться для рисования.

Теперь я также не понимаю, что в этом примере единственным представлением является PuzzleView. Я не уверен, как можно оптимизировать чертеж одного вида. Проверьте, обсуждается ли это далее в тексте.

Если это не так, то моя теория заключается в том, что объекты холста (прямоугольники) также являются частью указанного выше дерева, и рисуются только эти части, то есть прямоугольники в указанной области.

Что еще более важно, видите ли вы какое-либо улучшение после использования аннулирования области по сравнению с полным аннулированием?

person Sundeep    schedule 15.01.2014

Даже если вы вызовете недействительность несколько раз, метод onDraw будет вызван только один раз. В основном onDraw вызывается внутри метода RunLoop, когда представление становится недействительным. Это означает, что если вы сделаете представление недействительным несколько раз, прежде чем вернуть управление циклу выполнения, представление будет перерисовано только один раз. Обратите внимание, что если вы аннулируете два разных прямоугольника представления, система попытается объединить эти прямоугольники перед перерисовкой вашего представления.

person Pasquale Anatriello    schedule 16.01.2014

В коде недействительность, о которой вы говорите, такова:

  invalidate(selRect);

?

Если это так, он вызывает только onDraw этого выбранного прямоугольника selRect.

Только invalidate(); перерисовывает экран отверстия.

Надеюсь, поможет.

person Dyna    schedule 09.01.2014
comment
Пожалуйста, следите за комментариями к другому ответу и дайте ответ на мои вопросы, пожалуйста. Спасибо. - person Kraken; 09.01.2014

В этом примере вы должны заметить, что вызовы invalidate() имеют параметр Rect as. Это означает, что только эта зона вида загрязняется и будет перерисовываться системой.

Вызов invalidate() не вызовет сразу после этого метод onDraw(). Система только решает, когда он хочет перерисовать представление.

Из документации Android:

Если представление видимо, onDraw(android.graphics.Canvas) будет вызываться в какой-то момент в будущем.

Зная, что внутри метода select это, вероятно, произойдет: 1. Недействительная небольшая часть представления 2. Выполните некоторые действия 3. Недействительная другая небольшая часть представления 4. Тезисы 2 части представления перерисовываются

Надеюсь, это помогло.

person pdegand59    schedule 09.01.2014
comment
Некоторые логи я добавил в метод onDraw, некоторые при запуске, некоторые в цикле for. Всякий раз, когда я касался нового прямоугольника, вызывались все журналы. Разве это не означает, что весь экран заново заполняется? - person Kraken; 09.01.2014
comment
Когда я говорю весь экран, я имею в виду весь вид. - person Kraken; 09.01.2014
comment
Весь вид полностью не перерисовывается. В параметрах разработчика вашего устройства есть действительно полезная опция, которая заставляет экран мерцать всякий раз, когда он обновляется. Включите эту опцию, затем попробуйте коснуться только прямоугольника, и только этот прямоугольник (и второй) должен щелкнуть - person pdegand59; 09.01.2014
comment
Но как насчет журналов, если мои циклы выполняются, это означает, что весь canvas.draw тоже будет выполняться? Откуда система знает, какой кусок кода будет перерисовывать только грязную область? - person Kraken; 09.01.2014