Android 上的 ThreeTen-Backport 错误 - ZoneRulesException:未注册时区数据文件
Posted
技术标签:
【中文标题】Android 上的 ThreeTen-Backport 错误 - ZoneRulesException:未注册时区数据文件【英文标题】:ThreeTen-Backport error on Android - ZoneRulesException: No time-zone data files registered 【发布时间】:2016-11-11 22:00:29 【问题描述】:我正在为我的 android 项目使用 ThreeTen-Backport 库(因为 java.time 尚未在 android 开发中实现)。
当我写 LocalDate today=LocalDate.now();
或 LocalTime time=LocalTime.now();
时,我得到以下异常:
Caused by: org.threeten.bp.zone.ZoneRulesException:
No time-zone data files registered
at org.threeten.bp.zone.ZoneRulesProvider.getProvider(ZoneRulesProvider.java:176)
at org.threeten.bp.zone.ZoneRulesProvider.getRules(ZoneRulesProvider.java:133)
at org.threeten.bp.ZoneRegion.ofId(ZoneRegion.java:143)
at org.threeten.bp.ZoneId.of(ZoneId.java:357)
at org.threeten.bp.ZoneId.of(ZoneId.java:285)
at org.threeten.bp.ZoneId.systemDefault(ZoneId.java:244)
at org.threeten.bp.Clock.systemDefaultZone(Clock.java:137)
at org.threeten.bp.LocalDate.now(LocalDate.java:165)
同一行代码在我拥有的另一个 java 项目中运行良好,该项目使用本机 java.time 库。
我搜索了一个可能的解决方案,但找不到任何有用的解决方案:一个解决方案建议我需要使用另一个包含时区规则的 jar,而另一个解决方案建议类路径中可能有两个或多个 ThreeTenBP 库。 这些情况与我的情况不符。
在 build.gradle
文件的依赖项部分,我尝试了一些配置:
compile 'com.jakewharton.threetenabp:threetenabp:1.0.3'
然后,我尝试了——
compile 'org.threeten:threetenbp:1.0.3'
在那之后,我尝试了——
compile 'org.threeten:threetenbp:1.3.1'
目前,我使用compile 'org.threeten:threetenbp:1.3.2'
我不知道那行代码有什么问题以及如何修复它。LocalDate.now()
和 LocalTime.now()
方法应该可以在不指定时区的情况下工作。
【问题讨论】:
【参考方案1】:对于 Android 项目,您应该使用
implementation 'com.jakewharton.threetenabp:threetenabp:1.0.3'
确保在使用库中的类之前调用AndroidThreeTen.init(this);
。这将读取时区数据(包含在库中)。您可以在 onCreate
方法中的 Application
类中初始化库,就像在 README 中推荐的那样。
【讨论】:
谢谢,我的项目之前没有应用类,所以无法使用AndroidThreeTen.init(this);
代码。我想在活动的onCreate
方法中添加它,但我发现它不正确。现在我创建了一个扩展应用程序类的新类,并将该行放在onCreate
方法中。现在一切都很好!
在 onCreate 中调用 init 违反了严格模式,甚至会延迟应用启动。如果你异步调用 init,你必须确保在它完成之前不要使用它,这对于 JUnit 测试来说可能很困难。
@ErikB 它确实违反了严格模式,因为它从资产中读取时区文件,因此会延迟启动时间。对于单元测试,您应该使用原始库 threeten.org/threetenbp,因为这个库具有 Android 依赖项,如此处所述 github.com/JakeWharton/ThreeTenABP/issues/14
如何在单元测试中初始化这个库?
你没有。您只需添加原始的单元测试 (testImplementation
) 就可以了【参考方案2】:
你可以试试这个,而不是初始化库:
LocalDateEx.kt
object LocalDateEx
/**an alternative of LocalDate.now(), as it requires initialization using AndroidThreeTen.init(context), which takes a bit time (loads a file)*/
@JvmStatic
fun getNow(): LocalDate = Calendar.getInstance().toLocalDate()
fun Calendar.toLocalDate(): LocalDate = LocalDate.of(get(Calendar.YEAR), get(Calendar.MONTH) + 1, get(Calendar.DAY_OF_MONTH))
LocalTimeEx.kt
object LocalTimeEx
/**an alternative of LocalDateTime.now(), as it requires initialization using AndroidThreeTen.init(context), which takes a bit time (loads a file)*/
@JvmStatic
fun getNow(): LocalTime = Calendar.getInstance().toLocalTime()
fun Calendar.toLocalTime(): LocalTime = LocalTime.of(get(Calendar.HOUR_OF_DAY), get(Calendar.MINUTE), get(Calendar.SECOND), get(Calendar.MILLISECOND) * 1000000)
LocalDateTimeEx.kt
object LocalDateTimeEx
/**an alternative of LocalDateTime.now(), as it requires initialization using AndroidThreeTen.init(context), which takes a bit time (loads a file)*/
@JvmStatic
fun getNow(): LocalDateTime = Calendar.getInstance().toLocalDateTime()
private fun Calendar.toLocalDateTime(): LocalDateTime = LocalDateTime.of(get(Calendar.YEAR), get(Calendar.MONTH) + 1, get(Calendar.DAY_OF_MONTH), get(Calendar.HOUR_OF_DAY), get(Calendar.MINUTE), get(Calendar.SECOND),
get(Calendar.MILLISECOND) * 1000000)
用法:
val today=LocalDateEx.getNow()
val today2=LocalTimeEx.getNow()
val today3=LocalDateTimeEx.getNow()
【讨论】:
【参考方案3】:对我来说,它不适用于启用 proguard 的签名版本构建。检查你的 proguard 规则是否包含
-keep class org.threeten.bp.zone.*
除非,添加它。它对我有帮助。
【讨论】:
【参考方案4】:AGP 4.0 现在支持 Java 8 Desugar API,请参见此处:https://developer.android.com/studio/write/java8-support
因此您可以使用java.time.
而无需使用反向移植版本
注意事项:
如果您尝试支持低于 21 的 API 仍然存在问题(由 minSdk 21
解决):https://github.com/google/bundletool/issues/182#issuecomment-753269941
如官方文档中所述,脱糖还会增加构建时间
为了支持这些语言 API,插件会编译一个单独的 DEX 文件,其中包含缺失 API 的实现,并将其包含在您的应用中。脱糖过程会重写您的应用程序代码,以在运行时使用此库。
【讨论】:
【参考方案5】:当我使用 API 25 时 java.time 不起作用。使用 Jake Wharton 的threetenadp 做到了。所以这里有一个小更新,可以在 Studio 2020.3.1 上使用它
在 build.gradle 模块中
dependencies
implementation 'com.jakewharton.threetenabp:threetenabp:1.3.1'
import com.jakewharton.threetenabp.AndroidThreeTen
override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
AndroidThreeTen.init(application);
当 IDE 要求导入时,请务必选择 com.jakewharton.threetenabp.AndroidThreeTen 而不是 java.time
LocalTime.now().toSecondOfDay() 是我需要的。
【讨论】:
以上是关于Android 上的 ThreeTen-Backport 错误 - ZoneRulesException:未注册时区数据文件的主要内容,如果未能解决你的问题,请参考以下文章
ListView 上的 LongPress 与 Android 上的超链接
Android 9 上的 android.database.sqlite.SQLiteCantOpenDatabaseException