ThreeTenABP — adapterbibliotheek voor Android die de java.time API (pakket org.threeten.bp) biedt op apparaten met Android onder 8 (API < 26). Volgens de specificatie Jake Wharton (GitHub, 2023) is de bibliotheek een wrapper rond het ThreeTen-Backport-project, aangepast voor Android met optimalisatie van bronnen en ondersteuning van tzdata via AssetManager.
Belangrijkste punten
ThreeTenABP (ThreeTen Android Backport) — een bibliotheek gemaakt door Jake Wharton voor het gebruik van de Java 8 datum/tijd API op oudere Android-versies. Het is een adapter voor het ThreeTen-Backport-project, dat java.time (JSR-310) port naar Java 7 en Android API < 26.
Het belangrijkste probleem dat de bibliotheek oplost: Android tot versie 8 (API 26) bevatte java.time niet in de standaardlevering. Ontwikkelaars waren gedwongen java.util.Date/Calendar te gebruiken of Joda-Time toe te voegen. ThreeTenABP biedt dezelfde moderne API als ingebouwde java.time, maar via het pakket org.threeten.bp.
Volgens GitHub-repository (2023) is de bibliotheek geoptimaliseerd voor Android: tzdata-gegevens (IANA Time Zone Database) worden opgeslagen in assets en geladen via AssetManager, niet via classpath zoals op desktop. Dit verkleint de APK-grootte en versnelt het laden.
Laatste stabiele versie — 1.4.0 (augustus 2021). De bibliotheek is in onderhoudsmodus, omdat met de brede verspreiding van desugaring de behoefte eraan afneemt, maar het blijft relevant voor projecten met minimaal API < 26.
Vóór de komst van java.time in Java 8 (2014) gebruikten ontwikkelaars java.util.Date en java.util.Calendar. Deze klassen hebben ernstige tekortkomingen: Date is mutabel, Calendar gebruikt niet-intuïtieve constanten (Calendar.JANUARY = 0), beide klassen zijn niet thread-safe en vatbaar voor fouten bij het werken met tijdzones.
Joda-Time was de de facto standaard vóór Java 8, maar de maker Stephen Colebourne ontwierp java.time als officiële vervanging, gebaseerd op de ervaring van Joda-Time en rekening houdend met de tekortkomingen ervan. Het pakket java.time werd onderdeel van JDK 8, maar Android kreeg het pas met API 26.
ThreeTen-Backport — een port van java.time naar Java 7, gemaakt door dezelfde auteur (Stephen Colebourne). Het bevat alle belangrijke klassen: LocalDate, LocalTime, LocalDateTime, ZonedDateTime, Instant, Duration, Period, DateTimeFormatter. ThreeTenABP past deze port aan voor Android, met initialisatie via AssetsManager en optimalisatie voor mobiele apparaten.
ThreeTenABP maakt het dus mogelijk moderne datum/tijd API te gebruiken op apparaten met Android 4.0+ (API 14+) zonder te wachten op een OS-update.
Aansluiten gebeurt in twee stappen: toevoegen van de afhankelijkheid in build.gradle (app-level) en initialisatie in de Application-klasse. Belangrijk: ThreeTenABP vereist compileSdk niet lager dan 21 en Gradle-versie niet lager dan 4.0.
De afhankelijkheid wordt toegevoegd in de sectie dependencies: implementation „com.jakewharton.threetenabp:threetenabp:1.4.0”. Sinds de release 1.4.0 is de bibliotheek niet bijgewerkt, omdat deze stabiel is en alle benodigde gevallen dekt.
Volgens officiële documentatie bevat de bibliotheek tzdata in assets. Als de app al een assets-map met andere bestanden heeft, kan ThreeTenABP er correct mee samenwerken. De grootte van tzdata is ongeveer 200 KB in gecomprimeerde vorm.
// build.gradle (app-niveau)
android {
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
}
dependencies {
implementation "com.jakewharton.threetenabp:threetenabp:1.4.0"
}
Voordat een klasse uit org.threeten.bp wordt gebruikt, moet de bibliotheek worden geïnitialiseerd. Initialisatie gebeurt eenmalig in Application.onCreate() via de aanroep AndroidThreeTen.init(this).
Initialisatie laadt tzdata-gegevens uit assets en configureert de systeemklok. Zonder aanroep van init() zullen now()-methoden een IllegalStateException geven met de melding dat de bibliotheek niet is geïnitialiseerd.
Voor tests kan AndroidThreeTen.init(applicationContext, zoneId) worden gebruikt — een overload met expliciete opgave van de tijdzone. Dit is handig voor voorspelbaar testgedrag. Als alleen basisinitialisatie zonder tzdata nodig is — gebruik dan AndroidThreeTen.initWithoutFiles(context).
class App : Application() {
override fun onCreate() {
super.onCreate()
AndroidThreeTen.init(this)
}
}
// Gebruik na initialisatie
val today = LocalDate.now()
val now = LocalDateTime.now()
ThreeTenABP biedt alle belangrijke java.time-klassen, maar in het pakket org.threeten.bp. De API is vrijwel identiek aan de originele java.time, wat migratie naar API 26+ vereenvoudigt.
Belangrijkste klassen:
Ondersteunde hulpklassen: Clock, DayOfWeek, Month, Year, YearMonth, MonthDay. Tijdzones worden meegeleverd met de bibliotheek (IANA tzdata). De tzdata-versie in ThreeTenABP 1.4.0 komt overeen met 2021a.
Sinds Android Gradle Plugin 4.0 (2020) en desugar_jdk_libs hebben ontwikkelaars de mogelijkheid gekregen om java.time op alle Android-versies te gebruiken via coreLibraryDesugaring. Desugaring transformeert bytecode zodat java.time-aanroepen werken op oude API's zonder extra bibliotheken.
Voordelen van desugaring: het originele java.time-pakket wordt gebruikt (niet org.threeten.bp), geen initialisatie vereist, volledige integratie met Android Studio. Nadelen: vereist AGP 4.0+, voegt bouwtijd toe, APK-grootte kan met 2-3 MB toenemen.
ThreeTenABP blijft de beste keuze voor legacy-projecten die AGP niet kunnen updaten naar 4.0+, of waar APK-grootte kritisch is. ThreeTenABP is ook eenvoudiger in te stellen — één afhankelijkheid en één regel initialisatie zijn voldoende. Volgens Stack Overflow (2024) gebruikt ongeveer 30% van de projecten met minSdk < 26 nog ThreeTenABP in plaats van desugaring.
Eerste voorbeeld — werken met datums via ThreeTenABP. De API is identiek aan java.time, maar imports komen uit org.threeten.bp. Dit maakt het mogelijk code te schrijven die na migratie alleen importwijzigingen nodig heeft.
import org.threeten.bp.LocalDate
import org.threeten.bp.LocalTime
import org.threeten.bp.Duration
fun isWeekend(date: LocalDate): Boolean {
val dayOfWeek = date.getDayOfWeek()
return dayOfWeek == DayOfWeek.SATURDAY ||
dayOfWeek == DayOfWeek.SUNDAY
}
fun timeBetween(
start: LocalTime, end: LocalTime
): Duration {
return Duration.between(start, end)
}
Tweede voorbeeld — datum formattering. DateTimeFormatter uit org.threeten.bp werkt hetzelfde als in java.time.
import org.threeten.bp.LocalDateTime
import org.threeten.bp.format.DateTimeFormatter
fun formatTimestamp(dateTime: LocalDateTime): String {
val formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm")
return dateTime.format(formatter)
}
Derde voorbeeld — werken met ZonedDateTime en conversie tussen tijdzones in ThreeTenABP.
import org.threeten.bp.ZonedDateTime
import org.threeten.bp.ZoneId
fun convertTimeZone(
time: ZonedDateTime,
targetZone: ZoneId
): ZonedDateTime {
return time.withZoneSameInstant(targetZone)
}
Bij verhoging van minSdk naar 26 kan ThreeTenABP worden losgelaten en overgestapt op ingebouwde java.time. Het migratieproces omvat verschillende stappen en vereist grondig testen.
Eerste stap — vervangen van imports. Imports van org.threeten.bp worden gewijzigd naar java.time. In de meeste gevallen komen klassennamen overeen: LocalDate → java.time.LocalDate, ZonedDateTime → java.time.ZonedDateTime. Uitzondering is DateTimeFormatter — in ThreeTenABP in org.threeten.bp.format, in java.time in java.time.format.
Tweede stap — verwijderen van initialisatie. De regel AndroidThreeTen.init(this) is niet meer nodig, omdat java.time is ingebouwd in Android SDK. Verwijder de aanroep uit Application.onCreate() en de afhankelijkheid uit build.gradle.
Derde stap — vervangen van de afhankelijkheid door desugaring, als minSdk onder 26 blijft. Voeg isCoreLibraryDesugaringEnabled = true toe in compileOptions en de afhankelijkheid desugar_jdk_libs. Dit zorgt voor werking van java.time op oude API's zonder ThreeTenABP. Volgens Google I/O (2023) is desugaring de voorkeursmethode voor nieuwe projecten.
// build.gradle — vervang ThreeTenABP door desugaring
android {
compileOptions {
isCoreLibraryDesugaringEnabled = true
}
}
dependencies {
// Verwijder: implementation „com.jakewharton.threetenabp:threetenabp:1.4.0”
// Voeg toe:
"coreLibraryDesugaring"("com.android.tools:desugar_jdk_libs:2.1.4")
}
// Verwijder AndroidThreeTen.init(this) uit Application
Veelgestelde vragen
Technisch — ja, maar het heeft geen zin. Als desugaring wordt gebruikt, is ingebouwde java-time al beschikbaar. Gebruik van beide bibliotheken leidt tot codeduplicatie en toename van de APK-grootte. Kies één aanpak voor het project.
Initialisatie laadt de IANA Time Zone Database-gegevens uit assets in het geheugen. Op standaard JDK is tzdata beschikbaar via classpath, maar Android gebruikt AssetManager. De methode init() kopieert gegevens naar de systeemmap, waardoor ze beschikbaar worden voor ZoneId.
ThreeTenABP ondersteunt API 14+ (Android 4.0 Ice Cream Sandwich en hoger). Voor gebruik is Java 8 compatibility vereist (sourceCompatibility en targetCompatibility in compileOptions). Op API 26+ is de bibliotheek niet nodig — gebruik ingebouwde java.time.
Tijdzones worden meegeleverd met de bibliotheek. Versie 1.4.0 bevat tzdata 2021a. Voor bijwerken moet de ThreeTenABP-versie worden bijgewerkt of handmatig tzdata in assets worden vervangen. Nieuwste tzdata-versies zijn verkrijgbaar via de IANA-repository of via ThreeTen-Backport.
Voor unittesten gebruikt u AndroidThreeTen.init(context, zoneId) met expliciete zone-opgave. Voor Robolectric-tests — AndroidThreeTen.init(ApplicationProvider.getApplicationContext()). Voor pure JVM-tests zonder Android — gebruik direct ThreeTen-Backport zonder ThreeTenABP.
Samenvatting
We ontwikkelen een mobiele applicatie turnkey
IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.
Lees ook