ThreeTenABP — adapterbibliotek för Android, som tillhandahåller java.time API (paketet org.threeten.bp) på enheter med Android under 8 (API < 26). Enligt specifikationen Jake Wharton (GitHub, 2023) är biblioteket ett omslag kring projektet ThreeTen-Backport, anpassat för Android med hänsyn till resursoptimering och stöd för tzdata via AssetManager.
Huvudpunkter
ThreeTenABP (ThreeTen Android Backport) — ett bibliotek skapat av Jake Wharton för att använda Java 8 datum/tid API på äldre Android-versioner. Det är en adapter för projektet ThreeTen-Backport, som porterar java.time (JSR-310) till Java 7 och Android API < 26.
Huvudproblemet som biblioteket löser: Android upp till version 8 (API 26) inkluderade inte java.time i standardutbudet. Utvecklare var tvungna att använda java.util.Date/Calendar eller lägga till Joda-Time. ThreeTenABP tillhandahåller samma moderna API som inbyggd java.time, men via paketet org.threeten.bp.
Enligt GitHub-repository (2023) är biblioteket optimerat för Android: tzdata-data (IANA Time Zone Database) lagras i assets och laddas via AssetManager, inte via classpath som på skrivbordet. Detta minskar APK-storleken och snabbar upp laddningen.
Senaste stabila versionen — 1.4.0 (augusti 2021). Biblioteket är i supportläge, eftersom behovet av det minskar i takt med den breda spridningen av desugaring, men det förblir relevant för projekt med minimal API < 26.
Innan java.time kom i Java 8 (2014) använde utvecklare java.util.Date och java.util.Calendar. Dessa klasser har allvarliga brister: Date är muterbar, Calendar använder ointuitiva konstanter (Calendar.JANUARY = 0), båda klasserna är inte trådsäkra och benägna att fel vid arbete med tidszoner.
Joda-Time var de facto-standard före Java 8, men dess skapare Stephen Colebourne designade java.time som officiell ersättning, baserad på erfarenheterna från Joda-Time och med hänsyn till dess brister. Paketet java.time ingick i JDK 8, men Android fick det inte förrän API 26.
ThreeTen-Backport — en port av java.time till Java 7, skapad av samma författare (Stephen Colebourne). Den innehåller alla huvudklasser: LocalDate, LocalTime, LocalDateTime, ZonedDateTime, Instant, Duration, Period, DateTimeFormatter. ThreeTenABP anpassar denna port för Android, med initialisering via AssetsManager och optimering för mobila enheter.
ThreeTenABP gör det alltså möjligt att använda modernt datum/tid API på enheter med Android 4.0+ (API 14+) utan att vänta på en OS-uppdatering.
Anslutning görs i två steg: lägga till beroendet i build.gradle (app-level) och initialisering i Application-klassen. Viktigt: ThreeTenABP kräver compileSdk inte lägre än 21 och Gradle-version inte lägre än 4.0.
Beroendet läggs till i dependencies-sektionen: implementation ”com.jakewharton.threetenabp:threetenabp:1.4.0”. Sedan version 1.4.0 släpptes har biblioteket inte uppdaterats, eftersom det är stabilt och täcker alla nödvändiga fall.
Enligt officiell dokumentation innehåller biblioteket tzdata i assets. Om appen redan har en assets-mapp med andra filer samexisterar ThreeTenABP korrekt med dem. Tzdata är cirka 200 KB i komprimerad form.
// build.gradle (app-nivå)
android {
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
}
dependencies {
implementation "com.jakewharton.threetenabp:threetenabp:1.4.0"
}
Innan du använder någon klass från org.threeten.bp måste biblioteket initialiseras. Initialisering görs en gång i Application.onCreate() via anropet AndroidThreeTen.init(this).
Initialisering laddar tzdata-data från assets och konfigurerar systemklockan. Utan anrop till init() kommer now()-metoderna att kasta IllegalStateException med meddelande om att biblioteket inte är initialiserat.
För tester kan AndroidThreeTen.init(applicationContext, zoneId) användas — överlagring med explicit angivelse av tidszon. Detta är användbart för förutsägbart testbeteende. Om endast grundläggande initialisering utan tzdata behövs — använd AndroidThreeTen.initWithoutFiles(context).
class App : Application() {
override fun onCreate() {
super.onCreate()
AndroidThreeTen.init(this)
}
}
// Användning efter initialisering
val today = LocalDate.now()
val now = LocalDateTime.now()
ThreeTenABP tillhandahåller alla huvudklasser i java.time, men i paketet org.threeten.bp. API:et är praktiskt taget identiskt med ursprunglig java.time, vilket förenklar migrering vid övergång till API 26+.
Huvudklasser:
Även hjälpklasser stöds: Clock, DayOfWeek, Month, Year, YearMonth, MonthDay. Tidszoner levereras med biblioteket (IANA tzdata). Tzdata-versionen i ThreeTenABP 1.4.0 motsvarar 2021a.
Från och med Android Gradle Plugin 4.0 (2020) och desugar_jdk_libs har utvecklare fått möjlighet att använda java.time på alla Android-versioner via coreLibraryDesugaring. Desugaring transformerar bytekod så att java.time-anrop fungerar på gamla API:er utan extra bibliotek.
Fördelar med desugaring: det ursprungliga java.time-paketet används (inte org.threeten.bp), ingen initialisering krävs, full integration med Android Studio. Nackdelar: kräver AGP 4.0+, ökar byggtiden, APK-storleken kan öka med 2-3 MB.
ThreeTenABP förblir det bästa valet för legacy-projekt som inte kan uppdatera AGP till 4.0+, eller där APK-storlek är kritisk. ThreeTenABP är också enklare att konfigurera — ett beroende och en rad initialisering räcker. Enligt Stack Overflow (2024) använder cirka 30% av projekten med minSdk < 26 fortfarande ThreeTenABP istället för desugaring.
Första exemplet — arbete med datum via ThreeTenABP. API:et är identiskt med java.time, men importerna kommer från org.threeten.bp. Detta gör det möjligt att skriva kod som efter migrering endast kräver byte av importer.
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)
}
Andra exemplet — datumformatering. DateTimeFormatter från org.threeten.bp fungerar som i 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)
}
Tredje exemplet — arbete med ZonedDateTime och konvertering mellan tidszoner i ThreeTenABP.
import org.threeten.bp.ZonedDateTime
import org.threeten.bp.ZoneId
fun convertTimeZone(
time: ZonedDateTime,
targetZone: ZoneId
): ZonedDateTime {
return time.withZoneSameInstant(targetZone)
}
När minSdk höjs till 26 kan man lämna ThreeTenABP och gå över till inbyggd java.time. Migreringsprocessen omfattar flera steg och kräver noggrann testning.
Första steget — byte av importer. Importer från org.threeten.bp ändras till java.time. I de flesta fall överensstämmer klassnamnen: LocalDate → java.time.LocalDate, ZonedDateTime → java.time.ZonedDateTime. Undantaget är DateTimeFormatter — i ThreeTenABP är den i org.threeten.bp.format, i java.time — i java.time.format.
Andra steget — borttagning av initialisering. Rader AndroidThreeTen.init(this) behövs inte längre, eftersom java.time är inbyggt i Android SDK. Ta bort anropet från Application.onCreate() och beroendet från build.gradle.
Tredje steget — ersätt beroendet med desugaring, om minSdk förblir under 26. Lägg till isCoreLibraryDesugaringEnabled = true i compileOptions och beroendet desugar_jdk_libs. Detta säkerställer att java.time fungerar på gamla API:er utan ThreeTenABP. Enligt Google I/O (2023) är desugaring den föredragna metoden för nya projekt.
// build.gradle — ersätt ThreeTenABP med desugaring
android {
compileOptions {
isCoreLibraryDesugaringEnabled = true
}
}
dependencies {
// Ta bort: implementation ”com.jakewharton.threetenabp:threetenabp:1.4.0”
// Lägg till:
"coreLibraryDesugaring"("com.android.tools:desugar_jdk_libs:2.1.4")
}
// Ta bort AndroidThreeTen.init(this) från Application
Vanliga frågor
Tekniskt — ja, men det är inte meningsfullt. Om desugaring används är inbyggd java.time redan tillgänglig. Användning av båda biblioteken leder till kodduplicering och ökad APK-storlek. Välj en metod för projektet.
Initialisering laddar IANA Time Zone Database-data från assets till minnet. På standard JDK är tzdata tillgänglig via classpath, men Android använder AssetManager. Metoden init() kopierar data till systemkatalogen, vilket gör dem tillgängliga för ZoneId.
ThreeTenABP stöder API 14+ (Android 4.0 Ice Cream Sandwich och högre). För användning krävs Java 8 compatibility (sourceCompatibility och targetCompatibility i compileOptions). På API 26+ behövs inte biblioteket — använd inbyggd java.time.
Tidszoner levereras med biblioteket. Version 1.4.0 innehåller tzdata 2021a. För uppdatering måste ThreeTenABP-versionen uppdateras eller tzdata manuellt ersättas i assets. Senaste tzdata-versionerna kan hämtas från IANA-repository eller via ThreeTen-Backport.
För enhetstester, använd AndroidThreeTen.init(context, zoneId) med explicit zonangivelse. För Robolectric-tester — AndroidThreeTen.init(ApplicationProvider.getApplicationContext()). För rena JVM-tester utan Android — använd direkt ThreeTen-Backport utan ThreeTenABP.
Sammanfattning
Vi utvecklar en mobil applikation nyckelfärdigt
IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.
Läs också