#android #string
#Android #строка
Вопрос:
Я создаю игру, которая отображает некоторые цифры на холсте (счет, время и т.д.).
В настоящее время я делаю это с помощью команды drawtext на canvas
// score is some int
draw(Canvas c) {
c.drawText(score "", x, y, paintSyle);
}
Я слышал, что создание объекта и сборка мусора — дорогостоящие операции, и я думаю, что это создает новую строку при каждом ее вызове.
Прямо сейчас моя игра полностью рисует растровые изображения, и все скачет от 25 до 60 кадров в секунду. Я бы хотел, чтобы она оставалась ближе к большему числу, и я пытаюсь найти способы ускорить это.
Было бы быстрее / лучше создать (или найти?) какой-нибудь изменяемый подкласс string и обойти эту проблему? Есть ли другой способ решить эту проблему? Или это просто так?
Ответ №1:
Введите две новые private
переменные-члены String renderedScoreString
и int rederedScore
и перепишите свой draw()
метод следующим образом:
draw(Canvas c) {
if (this.score != this.renderedScore || this.renderedScoreString == null) {
this.renderedScore = this.score;
this.renderedScoreString = Integer.toString(this.renderedScore);
}
c.drawText(this.renderedScore, x, y, paintStyle);
}
это должно вас сильно сэкономить! создания объектов. Вы также могли бы скрыть шаблонный код за методом получения, например, String getScoreString()
который делает то же самое, поэтому у вас его нет в draw()
-методе.
Комментарии:
1. Спасибо, я вижу, как это будет работать для целого числа, такого как оценка, которое меняется не часто, но как насчет чего-то вроде time, которое меняется каждую секунду / миллисекунду? Мне действительно интересно, есть ли способ полностью избежать создания объекта. Также я думаю, что если я изменю renderedScoreString, где я изменил оценку, мне даже не пришлось бы выполнять проверку здесь.
2. если что-то меняется очень часто, всегда отображается и постоянно генерирует новые значения (не кэшируется), вам нужно создавать строковые объекты по мере необходимости. Иногда вы могли бы использовать следующее решение: кэшировать строковые объекты от 0 до 99 в hashmap и отображать время не за один
draw()
вызов. Пример:draw(stringMap[hours], ...); draw(stringMap[minutes], ...); draw(stringMap[seconds],...)
.stringMap
может быть простым массивом…
Ответ №2:
Мой друг подсказал мне решение этой проблемы. Когда вы хотите нарисовать что-то с течением времени, один из лучших (и простейших) механизмов для этого — разделить то, что вам нужно сделать, на два совершенно отдельных процесса.
ie. Используйте команду draw исключительно для рисования материалов, сведите логику / назначение в Draw () к абсолютному минимуму.
private final long TIMER_PERIOD = 500;
private String timeString;
private Runnable updateRunnable;
private Handler updateHandler = new Handler();
public void onCreate(Bundle savedInstanceState) {
updateRunnable = new Runnable() {
@Override
public void run() {
timeString = GetTimeString();
updateHandler.postDelayed(updateRunnable, TIMER_PERIOD);
}
}
}
Draw(Canvas c) {
c.drawText(timeString, x, y, paintStyle);
}
В этом примере команда рисования просто принимает timeString в его текущем состоянии и выводит его на экран. Это высокоэффективное использование функции рисования, поскольку она не требует создания какого-либо объекта, и в ней нет логики, которая не требуется немедленно для выполнения любого рисования. . В фоновом режиме Runnable выполняет функцию run() каждые 500 миллисекунд (приблизительно). Просто обновите функцию Run () с любой логикой, которая вам нужна для вычисления времени (в примере используется фиктивная функция GetTimeString()
)
Я надеюсь, что это полезно.
Комментарии:
1. GetTimeString по-прежнему будет создавать объекты каждые 1/2 секунды. Я думаю, это намного лучше, чем так быстро, как может рисовать программа. Я понимаю, что вы убрали ее из команды рисования, и это нормально, но когда я задавал вопрос (1,5 года назад : D), я пытался создать постоянное количество объектов.
Ответ №3:
Я знаю, что я восстанавливаю мертвый поток, но есть одна дополнительная оптимизация, которую вы можете добавить к этому, которая ограничивает создание строки одноразовым действием и, таким образом, запускает GC только один раз в начале, а не во время игры (что довольно важно для игры на Android).
Где-нибудь во время запуска вашей игры (onCreate, onResume, как часть синглтона во время запуска приложения и т.д.) Создайте большую строку [], Которая может содержать максимальное количество баллов (моя игра заполняет массив 10000, поэтому максимальное количество баллов будет равно 9999). Затем выполните цикл над ним с помощью цикла for, заполнив каждый индекс строкой.valueOf(i).
for (int i = 0; i <scoreStrings.length; i )
{
scoreStrings[i] = String.valueOf(i);
}
Теперь, когда вам нужно нарисовать партитуру, просто используйте int, который вы используете для сохранения партитуры в качестве индекса к этому массиву, и «эй, вуаля!», вы получите правильную строку для вашей партитуры.
canvas.drawText(scoreStrings[score], x, y, paint);