ThreeTenABP — библиотека-адаптер за Андроид, која пружа API java.time (пакет org.threeten.bp) на уређајима са Андроидом испод 8 (API < 26). Према спецификацији Jake Wharton (GitHub, 2023), библиотека је омотач пројекта ThreeTen-Backport, прилагођен за Андроид са оптимизацијом ресурса и подршком за tzdata преко AssetManager-а.
Главне тачке
ThreeTenABP (ThreeTen Android Backport) — библиотека коју је креирао Jake Wharton за коришћење API-ја за датум/време Java 8 на старијим верзијама Андроида. Она је адаптер за пројекат ThreeTen-Backport, који преноси java.time (JSR-310) на Java 7 и Android API < 26.
Главни проблем који библиотека решава: Андроид до верзије 8 (API 26) није укључивао java.time у стандардни пакет. Програмери су били принуђени да користе java.util.Date/Calendar или додају Joda-Time. ThreeTenABP пружа исти модерни API као уграђени java.time, али кроз пакет org.threeten.bp.
Према GitHub репозиторијуму (2023), библиотека је оптимизована за Андроид: tzdata подаци (IANA Time Zone Database) се чувају у assets-у и учитавају преко AssetManager-а, а не преко classpath-а као на десктопу. Ово смањује величину APK-а и убрзава учитавање.
Последња стабилна верзија — 1.4.0 (август 2021). Библиотека је у режиму подршке, јер са широким ширењем desugaring-а потреба за њом опада, али остаје актуелна за пројекте са минималним API < 26.
Пре појаве java.time у Java 8 (2014), програмери су користили java.util.Date и java.util.Calendar. Ове класе имају озбиљне недостатке: Date је мутабилан, Calendar користи неинтуитивне константе (Calendar.JANUARY = 0), обе класе нису thread-safe и склоне су грешкама при раду са временским зонама.
Joda-Time је био de facto стандард пре Java 8, али њен творац Stephen Colebourne је дизајнирао java.time као званичну замену, засновану на искуству Joda-Time и узимајући у обзир њене недостатке. Пакет java.time је ушао у JDK 8, али Андроид га није добио до API 26.
ThreeTen-Backport — порт java.time на Java 7, који је креирао исти аутор (Stephen Colebourne). Укључује све главне класе: LocalDate, LocalTime, LocalDateTime, ZonedDateTime, Instant, Duration, Period, DateTimeFormatter. ThreeTenABP прилагођава овај порт за Андроид, додајући иницијализацију преко AssetsManager-а и оптимизацију за мобилне уређаје.
Дакле, ThreeTenABP омогућава коришћење модерног API-ја за датум/време на уређајима са Андроид 4.0+ (API 14+) без чекања на ажурирање оперативног система.
Повезивање се врши у два корака: додавање зависности у build.gradle (app-level) и иницијализација у Application класи. Важно: ThreeTenABP захтева compileSdk не мањи од 21 и Gradle верзију не мању од 4.0.
Зависност се додаје у одељак dependencies: implementation „com.jakewharton.threetenabp:threetenabp:1.4.0”. Од издања 1.4.0 библиотека није ажурирана, јер је стабилна и покрива све потребне случајеве.
Према званичној документацији, библиотека укључује tzdata у assets-у. Ако апликација већ има фасциклу assets са другим датотекама, ThreeTenABP коректно коегзистира са њима. Величина tzdata је око 200 KB у компресованом облику.
// build.gradle (ниво апликације)
android {
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
}
dependencies {
implementation "com.jakewharton.threetenabp:threetenabp:1.4.0"
}
Пре коришћења било које класе из org.threeten.bp потребно је иницијализовати библиотеку. Иницијализација се врши једном у Application.onCreate() преко позива AndroidThreeTen.init(this).
Иницијализација учитава tzdata податке из assets-а и подешава системски сат. Без позива init() методе now() ће бацати изузетак IllegalStateException са поруком да библиотека није иницијализована.
За тестове се може користити AndroidThreeTen.init(applicationContext, zoneId) — преоптерећење са експлицитним навођењем временске зоне. Ово је корисно за предвидљиво понашање тестова. Ако је потребна само основна иницијализација без tzdata — користите AndroidThreeTen.initWithoutFiles(context).
class App : Application() {
override fun onCreate() {
super.onCreate()
AndroidThreeTen.init(this)
}
}
// Коришћење након иницијализације
val today = LocalDate.now()
val now = LocalDateTime.now()
ThreeTenABP пружа све главне класе java.time, али у пакету org.threeten.bp. API је практично идентичан оригиналном java.time, што олакшава миграцију при преласку на API 26+.
Главне класе:
Подржане су и помоћне класе: Clock, DayOfWeek, Month, Year, YearMonth, MonthDay. Временске зоне се испоручују са библиотеком (IANA tzdata). Верзија tzdata у ThreeTenABP 1.4.0 одговара 2021a.
Од Android Gradle Plugin 4.0 (2020) и desugar_jdk_libs, програмери су добили могућност коришћења java.time на свим верзијама Андроида преко coreLibraryDesugaring. Desugaring трансформише бајт-код тако да позиви java.time раде на старим API-јима без додатних библиотека.
Предности desugaring-а: користи се оригинални java.time пакет (не org.threeten.bp), није потребна иницијализација, потпуна интеграција са Android Studio. Недостаци: захтева AGP 4.0+, додаје време компајлирања, величина APK-а може порасти за 2-3 MB.
ThreeTenABP остаје најбољи избор за legacy пројекте који не могу ажурирати AGP на 4.0+, или где је величина APK-а критична. Такође, ThreeTenABP је једноставнији за подешавање — довољна је једна зависност и једна линија иницијализације. Према Stack Overflow (2024), око 30% пројеката са minSdk < 26 још увек користи ThreeTenABP уместо desugaring-а.
Први пример — рад са датумима преко ThreeTenABP. API је идентичан java.time, али импорти долазе из org.threeten.bp. Ово омогућава писање кода који након миграције захтева само замену импорта.
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)
}
Други пример — форматирање датума. DateTimeFormatter из org.threeten.bp ради исто као у 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)
}
Трећи пример — рад са ZonedDateTime и конверзија између временских зона у ThreeTenABP.
import org.threeten.bp.ZonedDateTime
import org.threeten.bp.ZoneId
fun convertTimeZone(
time: ZonedDateTime,
targetZone: ZoneId
): ZonedDateTime {
return time.withZoneSameInstant(targetZone)
}
При подизању minSdk на 26 може се одустати од ThreeTenABP и прећи на уграђени java.time. Процес миграције укључује неколико корака и захтева пажљиво тестирање.
Први корак — замена импорта. Импорти org.threeten.bp се мењају у java.time. У већини случајева имена класа се поклапају: LocalDate → java.time.LocalDate, ZonedDateTime → java.time.ZonedDateTime. Изузетак је DateTimeFormatter — у ThreeTenABP је у org.threeten.bp.format, у java.time — у java.time.format.
Други корак — уклањање иницијализације. Линија AndroidThreeTen.init(this) више није потребна, јер је java.time уграђен у Андроид SDK. Уклоните позив из Application.onCreate() и зависност из build.gradle-а.
Трећи корак — замена зависности на desugaring, ако minSdk остаје испод 26. Додајте isCoreLibraryDesugaringEnabled = true у compileOptions и зависност desugar_jdk_libs. Ово ће обезбедити рад java.time на старим API-јима без ThreeTenABP. Према Google I/O (2023), desugaring је пожељан метод за нове пројекте.
// build.gradle — замени ThreeTenABP desugaring-ом
android {
compileOptions {
isCoreLibraryDesugaringEnabled = true
}
}
dependencies {
// Уклони: implementation „com.jakewharton.threetenabp:threetenabp:1.4.0”
// Додај:
"coreLibraryDesugaring"("com.android.tools:desugar_jdk_libs:2.1.4")
}
// Уклони AndroidThreeTen.init(this) из Application
Често постављана питања
Технички — да, али нема смисла. Ако се користи desugaring, уграђени java.time је већ доступан. Коришћење обе библиотеке довешће до дуплирања кода и повећања величине APK-а. Изаберите један приступ за пројекат.
Иницијализација учитава IANA Time Zone Database податке из assets-а у меморију. На стандардном JDK-у tzdata је доступна преко classpath-а, али Андроид користи AssetManager. Метода init() копира податке у системски директоријум, чинећи их доступним за ZoneId.
ThreeTenABP подржава API 14+ (Android 4.0 Ice Cream Sandwich и новије). За коришћење је потребна Java 8 compatibility (sourceCompatibility и targetCompatibility у compileOptions). На API 26+ библиотека није потребна — користите уграђени java.time.
Временске зоне се испоручују са библиотеком. Верзија 1.4.0 укључује tzdata 2021a. За ажурирање потребно је ажурирати верзију ThreeTenABP или ручно заменити tzdata у assets-у. Најновије верзије tzdata могу се добити из IANA репозиторијума или преко ThreeTen-Backport-а.
За јединичне тестове користите AndroidThreeTen.init(context, zoneId) са експлицитним навођењем зоне. За Robolectric тестове — AndroidThreeTen.init(ApplicationProvider.getApplicationContext()). За чисте JVM тестове без Андроида — користите ThreeTen-Backport директно без ThreeTenABP.
Закључак
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође