SimpleDateFormat занимает слишком много времени при включении часового пояса


Я использую этот простой формат даты

    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS Z");

Проблема в том, что когда я использую это, требуется слишком много времени для преобразования времени, в logcat я вижу что-то вроде этого

I/Resources( 4284): Loaded time zone names for en in 272ms.
I/Resources( 4284): Loaded time zone names for en in 194ms.
I/Resources( 4284): Loaded time zone names for en in 112ms.
I/Resources( 4284): Loaded time zone names for en in 111ms.
I/Resources( 4284): Loaded time zone names for en in 113ms.
I/Resources( 4284): Loaded time zone names for en in 127ms.
I/Resources( 4284): Loaded time zone names for en in 253ms.
I/Resources( 4284): Loaded time zone names for en in 110ms.
I/Resources( 4284): Loaded time zone names for en in 154ms.
I/Resources( 4284): Loaded time zone names for en in 112ms.

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

У кого-нибудь раньше была такая проблема ?

2 7

2 ответа:

Это происходит из-за ленивой инициализации строк часовых поясов. Только первый звонок займет столько времени. Если SimpleDateFormat используется снова после этого это загружается из кэша и не должно занимать так много времени.

Прежде чем это было изменено, это было сделано, когда класс был загружен и, таким образом, начало активность занимала эти 2-3 секунды дольше. Это имело гораздо худшее влияние на пользователя опыт, чем если бы он занял те секунды, когда он фактически используется в первый раз. То проблема в том, что прямо сейчас нет способа обойти эту проблему из-за дизайна из класса simpledateformat API-интерфейс. Только более быстрые телефоны могли бы исправить это, просто взяв меньше пора собирать эти струны.

Кэширование происходит в DateFormatSymbols, которые использует SimpleDateFormat. Около повторное использование этого экземпляра возможно только для того, чтобы загрузить жала один раз (для тот же лоале). Вы также можете создать этот экземпляр в потоке при запуске программы. активность, чтобы она уже была кэширована как только он будет использован. Для инициализации строки просто позвоните .hashCode (), который заставляет инициализировать кэш. Немного быстрее, но не так просто было бы следует сериализовать экземпляр. Это также заставляет кэш инициализироваться.

В промежутке рассмотрите возможность использования AsyncTask для "разогрева" SimpleDateFormat в вашем процессе, прежде чем он вам понадобится. Просто проанализируйте некоторую дату в AsyncTask doInBackground (), чтобы заставить его загрузить часовые пояса когда-нибудь, когда это не будет так сильно влиять на пользователя. После инициализации в вашем процессе, SimpleDateFormat будет работать быстро, пока ваш процесс не будет завершен.

Это неверно в последних версиях Android (и из текста сообщения журнала я могу сказать, что вы запускаете старый релиз; современные релизы говорят вам, сколько времени было потрачено в icu4c по сравнению с управляемым кодом). Обратите внимание, что ответ от "Pulkit Goyal" был скопирован и вставлен из http://code.google.com/p/android/issues/detail?id=3147 и текст ссылается напончик . С тех пор я несколько раз переписывал этот код. В настоящее время en_US и локаль системы по умолчанию (при загрузке время) кэшируются в зиготе. Существует еще один кэш для каждого приложения, так что для других локалей вы должны заплатить только один раз.

Худший случай в современных версиях - это когда пользователь изменяет стандартную локаль системы. Это потребует перезапуска zygote ("runtime restart" или перезагрузка), чтобы получить строки часового пояса новой локали по умолчанию, кэшированные в zygote, где они могут быть совместно использованы. (я описал это поведение в комментарии 11 об ошибке, и оно поставляется с ICS.)