Android Java – Joda La fecha es lenta
Uso de Joda 1.6.2 con Android
El código siguiente se bloquea durante unos 15 segundos.
- Convertir milisegundo a Joda Fecha Hora o para zona 0000
- JodaTime - Compruebe si LocalTime es después de ahora y ahora antes de otro LocalTime
- Problemas con zona horaria incorrecta en Android
- Android: Proguard no compiló con el archivo jar de Joda Time
- JodaTime no reconoce algunas zonas horarias de Android
DateTime dt = new DateTime();
Originalmente publicado este post Android Java – Joda Fecha es lento en Eclipse / Emulador –
Acabo de probarlo de nuevo y su todavía no es mejor. ¿Alguien más tiene este problema o sabe cómo solucionarlo?
- Uso de la biblioteca Joda-Time para convertir la cadena al formato DateTime en Google Tasks API
- Hora de Joda y error de ProGuard al exportar .apk
- ProGuard no compiló con Joda Time utilizado en Windows
- Android java.lang.NoClassDefFoundError utilizando las bibliotecas JODA
- Añadiendo el tiempo de Joda
- Archivos duplicados copiados en APK al incluir Joda Time y bibliotecas de E / S comunes en el proyecto de Android
- Sólo algunos usuarios informan del error "Recurso no encontrado". ¿Esto tiene sentido?
- Pruebas unitarias y joda-time-android
También me encontré con este problema. Las sospechas de Jon Skeet eran correctas, el problema es que las zonas horarias se están cargando de manera muy ineficaz, abriendo un archivo jar y luego leyendo el manifiesto para tratar de obtener esta información.
Sin embargo, simplemente llamar a DateTimeZone.setProvider([custom provider instance ...])
no es suficiente porque, por razones que no tienen sentido para mí, DateTimeZone tiene un inicializador estático donde llama a getDefaultProvider()
.
Para estar completamente seguro, puede anular este valor predeterminado configurando esta propiedad del sistema antes de llamar a cualquier cosa en el joda.
En su actividad, por ejemplo, añada esto:
@Override public void onCreate(Bundle savedInstanceState) { System.setProperty("org.joda.time.DateTimeZone.Provider", "com.your.package.FastDateTimeZoneProvider"); }
Entonces todo lo que tienes que hacer es definir FastDateTimeZoneProvider
. Escribí lo siguiente:
package com.your.package; public class FastDateTimeZoneProvider implements Provider { public static final Set<String> AVAILABLE_IDS = new HashSet<String>(); static { AVAILABLE_IDS.addAll(Arrays.asList(TimeZone.getAvailableIDs())); } public DateTimeZone getZone(String id) { if (id == null) { return DateTimeZone.UTC; } TimeZone tz = TimeZone.getTimeZone(id); if (tz == null) { return DateTimeZone.UTC; } int rawOffset = tz.getRawOffset(); //sub-optimal. could be improved to only create a new Date every few minutes if (tz.inDaylightTime(new Date())) { rawOffset += tz.getDSTSavings(); } return DateTimeZone.forOffsetMillis(rawOffset); } public Set getAvailableIDs() { return AVAILABLE_IDS; } }
He probado esto y parece que funciona en Android SDK 2.1 + con joda versión 1.6.2. Por supuesto, se puede optimizar aún más, pero mientras perfilaba mi aplicación ( mogwee ), esto disminuyó el tiempo de inicialización de DateTimeZone de ~ 500ms a ~ 18ms.
Si está usando proguard para crear su aplicación, tendrá que agregar esta línea a proguard.cfg porque Joda espera que el nombre de la clase sea exactamente como usted especifica:
-keep class com.your.package.FastDateTimeZoneProvider
Creo firmemente que es porque tiene que construir la cronología ISO para la zona horaria por defecto, lo que probablemente implica la lectura de toda la información de zona horaria en.
Puede verificar esto llamando ISOChronology.getInstance()
primera vez que, y luego el tiempo de una llamada posterior a new DateTime()
. Sospecho que será rápido.
¿Sabe qué zonas horarias van a ser relevantes en su aplicación? Usted puede encontrar que puede hacer todo el asunto mucho más rápido reconstruyendo Joda Time con una base de datos de zona de tiempo muy reducido. Como alternativa, llame a DateTimeZone.setProvider()
con su propia implementación de Provider
que no hace tanto trabajo.
Vale la pena comprobar si en realidad es el problema primero, por supuesto 🙂 También puede intentar pasar explícitamente en la zona horaria UTC, que no requerirá la lectura en la base de datos de zona horaria … aunque nunca se sabe cuándo Activar accidentalmente una llamada que requiere la zona horaria predeterminada, momento en el que incurrirá en el mismo coste.
Sólo necesito UTC en mi aplicación. Así que, siguiendo el consejo de unchek, usé
System.setProperty("org.joda.time.DateTimeZone.Provider", "org.joda.time.tz.UTCProvider");
org.joda.time.tz.UTCProvider
es realmente utilizado por JodaTime como la copia de seguridad secundaria, así que pensé ¿por qué no usarlo para uso principal? Hasta aquí todo bien. Se carga rápido.
La respuesta superior proporcionada por plowman no es confiable si debe tener cálculos horarios precisos para sus fechas. Aquí hay un ejemplo de problema que puede ocurrir:
Supongamos que su objeto DateTime
está configurado para las 4:00 am, una hora después de que los ahorros de luz diurna hayan comenzado ese día. Cuando Joda comprueba el proveedor de FastDateTimeZoneProvider
antes de las 3:00 am (es decir, antes de los ahorros de luz) obtendrá un objeto DateTimeZone
con el desplazamiento incorrecto porque la tz.inDaylightTime(new Date())
devolverá false.
Mi solución fue adoptar la recientemente publicada joda-time-android library . Utiliza el núcleo de Joda, pero se asegura de cargar una zona horaria sólo según sea necesario desde la carpeta en bruto. La configuración es fácil con gradle. En su proyecto, extienda la clase Application
y añada lo siguiente en su onCreate()
:
public class MyApp extends Application { @Override public void onCreate() { super.onCreate(); JodaTimeAndroid.init(this); } }
El autor escribió un artículo sobre el blog el año pasado.
Puedo confirmar este problema con la versión 1, 1.5 y 1.62 de joda. Date4J está funcionando bien para mí como una alternativa.
Acabo de realizar la prueba que @ "Name is carl" publicado, en varios dispositivos. Debo señalar que la prueba no es completamente válida y los resultados son engañosos (en que sólo refleja una sola instancia de DateTime).
-
De su prueba, Cuando se compara DateTime con Date, DateTime se ve obligado a analizar el String ts, donde Date no analiza nada.
-
Mientras que la creación inicial del DateTime era exacta, toma SOLAMENTE ese mucho tiempo en la PRIMERA creación … cada ejemplo después de que era 0ms (o muy cerca de 0ms)
Para comprobar esto, utilicé el código siguiente y creé 1000 nuevas instancias de DateTime en un dispositivo Android 2.3
int iterations = 1000; long totalTime = 0; // Test Joda Date for (int i = 0; i < iterations; i++) { long d1 = System.currentTimeMillis(); DateTime d = new DateTime(); long d2 = System.currentTimeMillis(); long duration = (d2 - d1); totalTime += duration; log.i(TAG, "datetime : " + duration); } log.i(TAG, "Average datetime : " + ((double) totalTime/ (double) iterations));
Mis resultados mostraron:
Datetime: 264 Datetime: 0 Datetime: 0 Datetime: 0 Datetime: 0 Datetime: 0 Datetime: 0 ... Datetime: 0 Datetime: 0 Datetime: 1 Datetime: 0 ... Datetime: 0 Datetime: 0 Datetime: 0
Por lo tanto, el resultado fue que la primera instancia fue 264ms y más del 95% de los siguientes fueron 0ms (ocasionalmente tenía un 1 ms, pero nunca tuvo un valor mayor que 1ms).
Espero que esto da una imagen más clara del costo de usar Joda.
NOTA: Estaba usando joda-time versión 2.1
Encontré solución para mí. Cargo UTC y la zona horaria por defecto. Así que es muy rápido. Y creo que en este caso necesito capturar broadcast TIME ZONE CHANGE y recargar la zona horaria por defecto.
public class FastDateTimeZoneProvider implements Provider { public static final Set<String> AVAILABLE_IDS = new HashSet<String>(); static { AVAILABLE_IDS.add("UTC"); AVAILABLE_IDS.add(TimeZone.getDefault().getID()); } public DateTimeZone getZone(String id) { int rawOffset = 0; if (id == null) { return DateTimeZone.getDefault(); } TimeZone tz = TimeZone.getTimeZone(id); if (tz == null) { return DateTimeZone.getDefault(); } rawOffset = tz.getRawOffset(); //sub-optimal. could be improved to only create a new Date every few minutes if (tz.inDaylightTime(new Date())) { rawOffset += tz.getDSTSavings(); } return DateTimeZone.forOffsetMillis(rawOffset); } public Set getAvailableIDs() { return AVAILABLE_IDS; } }
Usando dlew / joda-tiempo-androide gradle dependencia que sólo toma 22,82 ms (milisegundos). Así que te recomiendo que lo uses en lugar de anular nada.
Esta nota rápida para completar la respuesta sobre date4j de @Steven
Corrí un punto de referencia rápido y sucio comparando java.util.Date
, jodatime
y date4j
en el dispositivo Android más débil que tengo (HTC Dream / Sapphire 2.3.5).
Detalles: normal build (no proguard), implementando el FastDateTimeZoneProvider
para jodatime.
Aquí está el código:
String ts = "2010-01-19T23:59:59.123456789"; long d1 = System.currentTimeMillis(); DateTime d = new DateTime(ts); long d2 = System.currentTimeMillis(); System.err.println("datetime : " + dateUtils.durationtoString(d2 - d1)); d1 = System.currentTimeMillis(); Date dd = new Date(); d2 = System.currentTimeMillis(); System.err.println("date : " + dateUtils.durationtoString(d2 - d1)); d1 = System.currentTimeMillis(); hirondelle.date4j.DateTime ddd = new hirondelle.date4j.DateTime(ts); d2 = System.currentTimeMillis(); System.err.println("date4j : " + dateUtils.durationtoString(d2 - d1));
Aquí están los resultados :
debug | normal joda : 3s (3577ms) | 0s (284ms) date : 0s (0) | 0s (0s) date4j : 0s (55ms) | 0s (2ms)
Una última cosa, los tamaños jar:
jodatime 2.1 : 558 kb date4j : 35 kb
Creo que voy a dar date4j un intento.
- Error de ADT de Android, dx.jar no se cargó desde la carpeta SDK
- GetSupportFragmentManager () no está definido