ThreeTenABP — adaptérová knihovna pro Android, poskytující API java.time (balíček org.threeten.bp) na zařízeních s Androidem pod 8 (API < 26). Podle specifikace Jake Wharton (GitHub, 2023) je knihovna obalem projektu ThreeTen-Backport, přizpůsobeným pro Android s ohledem na optimalizaci zdrojů a podporu tzdata prostřednictvím AssetManager.
Hlavní body
ThreeTenABP (ThreeTen Android Backport) — knihovna vytvořená Jakem Whartonem pro použití Java 8 API data/času na starších verzích Androidu. Jedná se o adaptér projektu ThreeTen-Backport, který portuje java.time (JSR-310) na Java 7 a Android API < 26.
Hlavní problém, který knihovna řeší: Android do verze 8 (API 26) nezahrnoval java.time ve standardní dodávce. Vývojáři byli nuceni používat java.util.Date/Calendar nebo přidávat Joda-Time. ThreeTenABP poskytuje stejné moderní API jako vestavěný java.time, ale prostřednictvím balíčku org.threeten.bp.
Podle GitHub repozitáře (2023) je knihovna optimalizována pro Android: data tzdata (IANA Time Zone Database) jsou uložena v assets a načítána přes AssetManager, nikoli přes classpath jako na desktopu. To snižuje velikost APK a urychluje načítání.
Poslední stabilní verze — 1.4.0 (srpen 2021). Knihovna je v režimu podpory, protože s rozšířením desugaring potřeba po ní klesá, ale zůstává relevantní pro projekty s minimálním API < 26.
Před příchodem java.time v Java 8 (2014) vývojáři používali java.util.Date a java.util.Calendar. Tyto třídy mají vážné nedostatky: Date je mutabilní, Calendar používá neintuitivní konstanty (Calendar.JANUARY = 0), obě třídy nejsou thread-safe a jsou náchylné k chybám při práci s časovými pásmy.
Joda-Time byla de facto standardem před Java 8, ale její tvůrce Stephen Colebourne navrhl java.time jako oficiální náhradu, založenou na zkušenostech s Joda-Time a zohledňující její nedostatky. Balíček java.time se stal součástí JDK 8, ale Android ho nezískal až do API 26.
ThreeTen-Backport — port java.time na Java 7, vytvořený stejným autorem (Stephen Colebourne). Zahrnuje všechny hlavní třídy: LocalDate, LocalTime, LocalDateTime, ZonedDateTime, Instant, Duration, Period, DateTimeFormatter. ThreeTenABP tento port přizpůsobuje pro Android, přidává inicializaci přes AssetsManager a optimalizaci pro mobilní zařízení.
ThreeTenABP tedy umožňuje používat moderní API data/času na zařízeních s Android 4.0+ (API 14+) bez čekání na aktualizaci OS.
Připojení se provádí ve dvou krocích: přidání závislosti do build.gradle (app-level) a inicializace v třídě Application. Důležité: ThreeTenABP vyžaduje compileSdk ne nižší než 21 a Gradle verzi ne nižší než 4.0.
Závislost se přidává do sekce dependencies: implementation „com.jakewharton.threetenabp:threetenabp:1.4.0”. Od vydání 1.4.0 knihovna nebyla aktualizována, protože je stabilní a pokrývá všechny potřebné případy.
Podle oficiální dokumentace knihovna obsahuje tzdata v assets. Pokud aplikace již má složku assets s jinými soubory, ThreeTenABP s nimi korektně koexistuje. Velikost tzdata je přibližně 200 KB v komprimované podobě.
// build.gradle (úroveň aplikace)
android {
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
}
dependencies {
implementation "com.jakewharton.threetenabp:threetenabp:1.4.0"
}
Před použitím jakékoli třídy z org.threeten.bp je třeba knihovnu inicializovat. Inicializace se provádí jednou v Application.onCreate() voláním AndroidThreeTen.init(this).
Inicializace načítá data tzdata z assets a konfiguruje systémové hodiny. Bez volání init() budou metody now() vyhazovat výjimku IllegalStateException s oznámením, že knihovna není inicializována.
Pro testy lze použít AndroidThreeTen.init(applicationContext, zoneId) — přetížení s explicitním určením časového pásma. To je užitečné pro předvídatelné chování testů. Pokud je potřeba pouze základní inicializace bez tzdata — použijte AndroidThreeTen.initWithoutFiles(context).
class App : Application() {
override fun onCreate() {
super.onCreate()
AndroidThreeTen.init(this)
}
}
// Použití po inicializaci
val today = LocalDate.now()
val now = LocalDateTime.now()
ThreeTenABP poskytuje všechny hlavní třídy java.time, ale v balíčku org.threeten.bp. API je prakticky identické s původním java.time, což usnadňuje migraci při přechodu na API 26+.
Hlavní třídy:
Podporovány jsou také pomocné třídy: Clock, DayOfWeek, Month, Year, YearMonth, MonthDay. Časová pásma jsou dodávána s knihovnou (IANA tzdata). Verze tzdata v ThreeTenABP 1.4.0 odpovídá 2021a.
Od Android Gradle Plugin 4.0 (2020) a desugar_jdk_libs získali vývojáři možnost používat java.time na všech verzích Androidu prostřednictvím coreLibraryDesugaring. Desugaring transformuje bytecode tak, že volání java.time fungují na starých API bez dalších knihoven.
Výhody desugaring: používá se původní balíček java.time (ne org.threeten.bp), nevyžaduje inicializaci, plná integrace s Android Studio. Nevýhody: vyžaduje AGP 4.0+, přidává čas sestavení, velikost APK může vzrůst o 2-3 MB.
ThreeTenABP zůstává nejlepší volbou pro legacy projekty, které nemohou aktualizovat AGP na 4.0+, nebo kde je velikost APK kritická. ThreeTenABP je také jednodušší na nastavení — jedna závislost a jeden řádek inicializace stačí. Podle Stack Overflow (2024) asi 30 % projektů s minSdk < 26 stále používá ThreeTenABP místo desugaring.
První příklad — práce s daty přes ThreeTenABP. API je identické s java.time, ale importy pocházejí z org.threeten.bp. To umožňuje psát kód, který po migraci vyžaduje pouze výměnu importů.
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)
}
Druhý příklad — formátování data. DateTimeFormatter z org.threeten.bp funguje stejně jako v 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)
}
Třetí příklad — práce s ZonedDateTime a konverze mezi časovými pásmy v ThreeTenABP.
import org.threeten.bp.ZonedDateTime
import org.threeten.bp.ZoneId
fun convertTimeZone(
time: ZonedDateTime,
targetZone: ZoneId
): ZonedDateTime {
return time.withZoneSameInstant(targetZone)
}
Při zvýšení minSdk na 26 lze opustit ThreeTenABP a přejít na vestavěný java.time. Proces migrace zahrnuje několik kroků a vyžaduje důkladné testování.
První krok — výměna importů. Importy org.threeten.bp se mění na java.time. Ve většině případů se názvy tříd shodují: LocalDate → java.time.LocalDate, ZonedDateTime → java.time.ZonedDateTime. Výjimkou je DateTimeFormatter — v ThreeTenABP je v org.threeten.bp.format, v java.time — v java.time.format.
Druhý krok — odstranění inicializace. Řádek AndroidThreeTen.init(this) již není potřeba, protože java.time je vestavěn v Android SDK. Odstraňte volání z Application.onCreate() a závislost z build.gradle.
Třetí krok — nahrazení závislosti desugaringem, pokud minSdk zůstává pod 26. Přidejte isCoreLibraryDesugaringEnabled = true v compileOptions a závislost desugar_jdk_libs. To zajistí fungování java.time na starých API bez ThreeTenABP. Podle Google I/O (2023) je desugaring preferovaným způsobem pro nové projekty.
// build.gradle — nahraďte ThreeTenABP desugaringem
android {
compileOptions {
isCoreLibraryDesugaringEnabled = true
}
}
dependencies {
// Odstraňte: implementation „com.jakewharton.threetenabp:threetenabp:1.4.0”
// Přidejte:
"coreLibraryDesugaring"("com.android.tools:desugar_jdk_libs:2.1.4")
}
// Odstraňte AndroidThreeTen.init(this) z Application
Často kladené otázky
Technicky — ano, ale nemá to smysl. Pokud se používá desugaring, vestavěný java.time je již dostupný. Použití obou knihoven povede k duplicitě kódu a zvýšení velikosti APK. Vyberte jeden přístup pro projekt.
Inicializace načítá data IANA Time Zone Database z assets do paměti. Na standardním JDK je tzdata dostupná přes classpath, ale Android používá AssetManager. Metoda init() kopíruje data do systémového adresáře, čímž je zpřístupňuje pro ZoneId.
ThreeTenABP podporuje API 14+ (Android 4.0 Ice Cream Sandwich a vyšší). Pro použití je vyžadována Java 8 compatibility (sourceCompatibility a targetCompatibility v compileOptions). Na API 26+ knihovna není potřeba — použijte vestavěný java.time.
Časová pásma jsou dodávána s knihovnou. Verze 1.4.0 obsahuje tzdata 2021a. Pro aktualizaci je třeba aktualizovat verzi ThreeTenABP nebo ručně nahradit tzdata v assets. Nejnovější verze tzdata lze získat z repozitáře IANA nebo přes ThreeTen-Backport.
Pro unit testy použijte AndroidThreeTen.init(context, zoneId) s explicitním určením zóny. Pro Robolectric testy — AndroidThreeTen.init(ApplicationProvider.getApplicationContext()). Pro čisté JVM testy bez Androidu — použijte přímo ThreeTen-Backport bez ThreeTenABP.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také