ThreeTenABP — کتابخانه آداپتور برای Android، ارائهدهنده API java.time (بسته org.threeten.bp) در دستگاههای با Android زیر ۸ (API < 26). بر اساس مشخصات Jake Wharton (GitHub, 2023)، این کتابخانه پوششی بر روی پروژه ThreeTen-Backport است که برای Android با در نظر گرفتن بهینهسازی منابع و پشتیبانی tzdata از طریق AssetManager تطبیق داده شده است.
نکات اصلی
ThreeTenABP (ThreeTen Android Backport) — کتابخانهای ساخته شده توسط Jake Wharton برای استفاده از API تاریخ/زمان Java 8 در نسخههای قدیمی Android. این کتابخانه آداپتوری برای پروژه ThreeTen-Backport است که java.time (JSR-310) را به Java 7 و Android API < 26 منتقل میکند.
مشکل اصلی که کتابخانه حل میکند: Android تا نسخه ۸ (API 26) java.time را در بسته استاندارد خود نداشت. توسعهدهندگان مجبور به استفاده از java.util.Date/Calendar یا اضافه کردن Joda-Time بودند. ThreeTenABP همان API مدرن java.time داخلی را ارائه میدهد، اما از طریق بسته org.threeten.bp.
بر اساس مخزن GitHub (2023)، کتابخانه برای Android بهینه شده است: دادههای tzdata (IANA Time Zone Database) در assets ذخیره شده و از طریق AssetManager بارگذاری میشوند، نه از طریق classpath مانند دسکتاپ. این کار اندازه APK را کاهش داده و بارگذاری را سریعتر میکند.
آخرین نسخه پایدار — 1.4.0 (اوت 2021). کتابخانه در حالت پشتیبانی قرار دارد، زیرا با گسترش desugaring نیاز به آن کاهش مییابد، اما همچنان برای پروژههایی با حداقل API < 26 relevant است.
پیش از ظهور 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 شد، اما Android تا API 26 آن را دریافت نکرد.
ThreeTen-Backport — پورت java.time به Java 7 است که توسط همان نویسنده (Stephen Colebourne) ساخته شده است. این شامل تمام کلاسهای اصلی است: LocalDate, LocalTime, LocalDateTime, ZonedDateTime, Instant, Duration, Period, DateTimeFormatter. ThreeTenABP این پورت را برای Android تطبیق میدهد و مقداردهی اولیه از طریق AssetsManager و بهینهسازی برای دستگاههای همراه را اضافه میکند.
بنابراین، ThreeTenABP امکان استفاده از API مدرن تاریخ/زمان را در دستگاههای Android 4.0+ (API 14+) بدون نیاز به انتظار برای بهروزرسانی سیستم عامل فراهم میکند.
اتصال در دو مرحله انجام میشود: اضافه کردن وابستگی در build.gradle (app-level) و مقداردهی اولیه در کلاس Application. مهم: ThreeTenABP به compileSdk کمتر از ۲۱ و Gradle نسخه کمتر از ۴.۰ نیاز دارد.
وابستگی در بخش dependencies اضافه میشود: implementation «com.jakewharton.threetenabp:threetenabp:1.4.0». از زمان انتشار 1.4.0 کتابخانه بهروزرسانی نشده است، زیرا پایدار است و تمام موارد لازم را پوشش میدهد.
بر اساس مستندات رسمی، کتابخانه شامل tzdata در assets است. اگر برنامه از قبل پوشه assets با فایلهای دیگر دارد، ThreeTenABP به درستی با آنها همزیستی میکند. اندازه tzdata حدود ۲۰۰ کیلوبایت در حالت فشرده است.
// 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) استفاده کرد — overload با مشخص کردن صریح منطقه زمانی. این برای رفتار قابل پیشبینی تستها مفید است. اگر فقط مقداردهی اولیه پایه بدون 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 را در تمام نسخههای Android از طریق coreLibraryDesugaring دریافت کردند. Desugaring بایتکد را به گونهای تبدیل میکند که فراخوانیهای java.time در APIهای قدیمی بدون کتابخانههای اضافی کار کنند.
مزایای desugaring: استفاده از بسته اصلی java.time (نه org.threeten.bp)، عدم نیاز به مقداردهی اولیه، یکپارچگی کامل با Android Studio. معایب: نیاز به AGP 4.0+، افزایش زمان ساخت، اندازه APK ممکن است ۲-۳ مگابایت افزایش یابد.
ThreeTenABP بهترین انتخاب برای پروژههای legacy باقی میماند که نمیتوانند AGP را به ۴.۰+ بهروزرسانی کنند، یا جایی که اندازه APK بحرانی است. همچنین ThreeTenABP در تنظیمات سادهتر است — یک وابستگی و یک خط مقداردهی اولیه کافی است. طبق Stack Overflow (2024)، حدود ۳۰٪ از پروژههای با minSdk < 26 هنوز از ThreeTenABP به جای desugaring استفاده میکنند.
اولین نمونه — کار با تاریخها از طریق ThreeTenABP. API مشابه java.time است، اما importها از org.threeten.bp میآیند. این امکان نوشتن کدی را فراهم میکند که پس از مهاجرت فقط نیاز به تغییر 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)
}
دومین نمونه — قالببندی تاریخ. 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 به ۲۶ میتوان از ThreeTenABP صرف نظر کرده و به java.time داخلی مهاجرت کرد. فرآیند مهاجرت شامل چند مرحله است و نیاز به تست دقیق دارد.
اولین مرحله — جایگزینی importها. importهای 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 در Android SDK داخلی است. فراخوانی را از Application.onCreate() و وابستگی را از build.gradle حذف کنید.
سومین مرحله — جایگزینی وابستگی با desugaring، اگر minSdk زیر ۲۶ باقی بماند. 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 در دسترس است، اما Android از AssetManager استفاده میکند. متد init() دادهها را به دایرکتوری سیستم کپی میکند و آنها را برای ZoneId قابل دسترس میسازد.
ThreeTenABP از API 14+ (Android 4.0 Ice Cream Sandwich و بالاتر) پشتیبانی میکند. برای استفاده Java 8 compatibility (sourceCompatibility و targetCompatibility در compileOptions) لازم است. در API 26+ کتابخانه نیاز نیست — از java.time داخلی استفاده کنید.
مناطق زمانی به همراه کتابخانه ارائه میشوند. نسخه ۱.۴.۰ شامل tzdata 2021a است. برای بهروزرسانی باید نسخه ThreeTenABP را بهروز کنید یا tzdata را در assets به صورت دستی جایگزین کنید. آخرین نسخههای tzdata را میتوان از مخزن IANA یا از طریق ThreeTen-Backport دریافت کرد.
برای تستهای واحد از AndroidThreeTen.init(context, zoneId) با مشخص کردن صریح منطقه استفاده کنید. برای تستهای Robolectric — AndroidThreeTen.init(ApplicationProvider.getApplicationContext()). برای تستهای JVM خالص بدون Android — مستقیماً از ThreeTen-Backport بدون ThreeTenABP استفاده کنید.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید