Android 上的 ThreeTen-Backport 错误 - ZoneRulesException:未注册时区数据文件

ThreeTen-Backport error on Android - ZoneRulesException: No time-zone data files registered

我正在为我的 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 文件的依赖项部分,我尝试了一些配置:

我不知道那行代码有什么问题以及如何解决它。
LocalDate.now()LocalTime.now() 方法应该在不指定时区的情况下工作。

对于 Android 项目,您应该使用

implementation 'com.jakewharton.threetenabp:threetenabp:1.0.3'

确保在使用库中的 class 之前调用 AndroidThreeTen.init(this);。这将读取时区数据(包含在库中)。您可以在 Application class 中使用 onCreate 方法初始化库,就像在 README.

中推荐的那样

除了初始化库,你可以试试这个:

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()

对我来说,它不适用于启用混淆器的签名版本。检查你的 proguard 规则是否包含

-keep class org.threeten.bp.zone.*

除非,加上。它对我有帮助。

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

如官方文档所述,脱糖也会增加构建时间

To support these language APIs, the plugin compiles a separate DEX file that contains an implementation of the missing APIs and includes it in your app. The desugaring process rewrites your app’s code to instead use this library at runtime.

当我使用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() 是我需要的。