如何在Android项目中使用ThreeTenABP

How to use ThreeTenABP in Android Project

提问人:kael 提问时间:8/13/2016 最后编辑:starballkael 更新时间:10/27/2023 访问量:40494

问:

我使用的是 Android Studio 2.1.2,我的 Java 设置如下:

>java -version
> openjdk version "1.8.0_91"
> OpenJDK Runtime Environment (build 1.8.0_91-8u91-b14-3ubuntu1~15.10.1-b14)
> OpenJDK 64-Bit Server VM (build 25.91-b14, mixed mode)

我找了几个小时试图弄清楚这一点。答案来自相关答案的组合,所以我想我会把我学到的东西记录下来,给其他可能正在挣扎的人。查看答案。

日期时间 android-gradle-plugin threetenbp threetenabp

评论


答:

229赞 kael 8/13/2016 #1

注意:这个答案虽然在技术上是正确的,但现在已经过时了

Java 8+ API 脱糖支持现已通过 Android Gradle 插件 4.0.0+ 提供

(另请参阅下面Basil Bourque的回答)

ThreeTenABP库的开发正在结束.请考虑在未来几个月内切换到 Android Gradle 插件 4.0、java.time.* 及其核心库脱糖功能。

如需在任何版本的 Android 平台上启用对这些语言 API 的支持,请将 Android 插件更新到 4.0.0(或更高版本),并在模块的 build.gradle 文件中包含以下内容(来自 Android 开发者网站上 Java 8 支持页面的这一部分,其中还包含有关脱糖的其他信息):

android {
  defaultConfig {
    // Required when setting minSdkVersion to 20 or lower
    multiDexEnabled true
  }

  compileOptions {
    // Flag to enable support for the new language APIs
    coreLibraryDesugaringEnabled true
    // Sets Java compatibility to Java 8
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
  }
}

dependencies {
  coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.0.5'
}

原始答案

第一个发现:为什么你必须使用ThreeTenABP而不是java.time,ThreeTen-backport,甚至Joda-Time

这是定义新标准的“非常长”过程的一个非常简短的版本。所有这些包几乎都是一样的:为 Java 提供良好的现代时间处理功能的库。差异是微妙的,但很重要。

最明显的解决方案是使用内置的 java.time 包,因为这是在 Java 中处理时间和日期的新标准方法。它是 JSR 310 的实现,JSR 310 是基于 Joda-Time 库的时间处理的新标准提案。

但是,是在 Java 8 中引入的。Android 直到 Marshmallow 在 Java 7 上运行(“Android N”是第一个引入 Java 8 语言功能的版本)。因此,除非你只针对 Android N Nougat 及更高版本,否则你不能依赖 Java 8 语言功能(我实际上不确定这是否 100% 正确,但这就是我的理解)。所以出来了。java.timejava.time

下一个选项可能是 Joda-Time,因为 JSR 310 是基于 Joda-Time 的。然而,正如 ThreeTenABP 自述文件所指出的那样,由于多种原因,Joda-Time 并不是最佳选择。

接下来是 ThreeTen-Backport,它将大部分(但不是全部)Java 8 功能向后移植到 Java 7。这对于大多数用例来说都很好,但是,正如 ThreeTenABP 自述文件中所指出的,它在 Android 上存在性能问题。java.time

因此,最后一个看似正确的选项是 ThreeTenABP

第二个发现:构建工具和依赖项管理

由于编译程序(尤其是使用一堆外部库的程序)很复杂,因此 Java 几乎总是使用“构建工具”来管理该过程。Make、Apache AntApache MavenGradle 都是与 Java 程序一起使用的构建工具(有关比较,请参阅这篇文章)。如下所述,Gradle 是 Android 项目的首选构建工具。

这些生成工具包括依赖项管理。Apache Maven 似乎是第一个包含集中式包存储库的。Maven 引入了 Maven 中央存储库,它允许的功能相当于 php 的 Packagist 和 Ruby 的 rubygems.org。换句话说,Maven Central Repository 之于 Maven(和 Gradle)就像 Packagist 之于 composer 一样——版本化包的权威且安全的来源。composergem

第三个发现:Gradle 处理 Android 项目中的依赖项

在我的待办事项清单上,最重要的是阅读 Gradle 文档,包括他们的免费电子书。如果我在几周前开始学习 Android 时阅读了这些内容,我肯定会知道 Gradle 可以使用 Maven Central Repository 来管理 Android 项目中的依赖项。此外,正如 StackOverflow 答案中所详述的那样,从 Android Studio 0.8.9 开始,Gradle 通过 Bintray 的 JCenter 隐式使用 Maven Central Repository,这意味着您无需进行任何额外的配置即可设置 repo——您只需列出依赖项即可。

第四次发现:项目依赖项列在 [project dir]/app/build.gradle 中

同样,对于那些在 Java 中使用 Gradle 的人来说,这是显而易见的,但我花了一段时间才弄清楚这一点。如果您看到有人说“哦,只需添加”或类似内容,请知道这是该 build.gradle 文件中指示编译时依赖项的指令。这是关于依赖项管理的官方 Gradle 页面。compile 'this-or-that.jar'compile

第五个发现:ThreeTenABP由Jake Wharton管理,而不是由ThreeTen

另一个问题我花了太多时间弄清楚。如果您在 Maven Central 中查找 ThreeTen,则只会看到 的包,而不会看到 。如果你去 ThreeTenABP 的 github 存储库,你会在自述文件的下载部分看到那一行臭名昭著的行。threetenbpthreetenabpcompile 'this-or-that'

当我第一次点击这个 github 存储库时,我不知道那行编译是什么意思,我试图在我的终端中运行它(有一个明显且可预测的失败)。沮丧的是,直到我弄清楚其余部分很久之后,我才回到它,最后意识到这是指向 repo 的 Maven Repo 行,而不是 repo。这就是为什么我认为 ThreeTenABP 包不在 Maven 存储库中的原因。com.jakewharton.threetenabporg.threeten

摘要:让它发挥作用

现在一切似乎都很容易。您可以通过确保您的文件在其部分中有以下行来获得 Android 项目中的现代时间处理函数:[project folder]/app/build.gradleimplementation 'com.jakewharton.threetenabp:threetenabp:1.2.1'dependencies

apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.3"

    defaultConfig {
        applicationId "me.ahuman.myapp"
        minSdkVersion 11
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}


dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    testImplementation 'junit:junit:4.12'
    implementation 'com.android.support:appcompat-v7:23.4.0'
    implementation 'com.android.support:design:23.4.0'
    implementation 'com.jakewharton.threetenabp:threetenabp:1.2.1'
}

同时将此添加到 Application 类中:

public class App extends Application {    
    @Override
    public void onCreate() {
        super.onCreate();
        AndroidThreeTen.init(this);
        //...
    }
}

评论

1赞 Bob 8/26/2017
感谢您的精彩帖子。但是,我想知道您是否也考虑过JodaTimeAndroid
0赞 kael 8/30/2017
@Bob,我还没有尝试过 JodaTimeAndroid,但这只是因为我现在并没有真正做任何需要它的事情。据我所知,实现很好(基本上是 JodaTime 的一个端口),我相信再过一两年,90% 的用户将使用 Nougat+,使其成为可行的开发解决方案。java.time
2赞 M. Prokhorov 11/28/2017
@Bob,JodaTime 与 JSR-310 基本相同(甚至基本上由同一个人制作),只是 JSR-310 的设计缺陷更少(例如,参见本文)。[...继续下文]
2赞 Basil Bourque 1/14/2018
澄清评论...java.time 框架 (JSR 310) 是 Joda-Time 项目的正式继承者。这两个项目都由同一个人斯蒂芬·科尔伯恩(Stephen Colebourne)领导。Joda-Time 项目现在处于维护模式,团队建议迁移到 java.time。
7赞 Anonymous 10/9/2018
请确保在使用 API 之前进行调用,例如在 中。请参阅 Android 上的 ThreeTen-Backport 错误 - ZoneRulesException:未注册时区数据文件AndroidThreeTen.init(this)onCreate()
8赞 Richard Kamere 8/19/2019 #2

在 Android Studio 的构建 gradle(模块级别)文件中添加以下内容:

implementation 'com.jakewharton.threetenabp:threetenabp:1.2.1'

创建 Application 类并初始化它,如下所示:

class App : Application() {
    override fun onCreate() {
        super.onCreate()
        AndroidThreeTen.init(this)
    }
}
18赞 Basil Bourque 5/5/2020 #3

凯尔接受的答案是正确的。此外,我将提到几件事,并提供一个关于获取 java.time 功能的图表。

java.time 内置于 Android 26+ 中

如果以 Android 26 或更高版本为目标平台,您会发现 JSR 310java.time 类)的实现与 Android 捆绑在一起。无需添加ThreeTenABP.

API 几乎相同

澄清一下,ThreeTenABP for Android 是 ThreeTen-Backport 库的改编版,它将大部分 java.time 功能带到了 Java 6Java 7 中。这个向后移植与 java.time 共享几乎相同的 API。

假设您现在的目标是早于 26 的 Android,因此您使用 ThreeTenABP.之后,您最终可能会放弃对这些早期版本的 Android 的支持,以使用与 Android 捆绑在一起的 java.time 类。发生这种情况时,除了 (a) switch 语句和 (b) 更改对 org.threeten.bp.DateTimeUtils 所做的任何调用以使用添加到旧旧日期时间类 (, ) 的新转换方法之外,您只需要对代码库进行少量更改。importDateGregorianCalendar

ThreeTenABPjava.time 的过渡过程应该是平稳的,几乎是无痛的。

何时使用哪个框架

下面是一个图表,显示了这三个框架,并指示何时在哪些场景中使用哪个框架。

➥ 更新:Android Gradle 插件 4.0.0+ 带来了新的第 4 个选项,即 API 脱糖,以提供最初未内置于早期 Android 中的 java.time 功能子集。参见 kael 的主要答案的顶部。

Table of which java.time library to use with which version of Java or Android


关于java.time

java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧日期时间类,如java.util.DateCalendarSimpleDateFormat

要了解更多信息,请参阅 Oracle 教程。并在 Stack Overflow 中搜索许多示例和解释。规范是 JSR 310

Joda-Time项目现在处于维护模式,建议迁移到java.time类。

您可以直接与数据库交换 java.time 对象。使用符合 JDBC 4.2 或更高版本的 JDBC 驱动程序。不需要字符串,不需要类。Hibernate 5 和 JPA 2.2 支持 java.timejava.sql.*

从哪里获取 java.time 类?

评论

0赞 Raw Hasan 9/1/2021
我对在 Kotlin 中使用日期/时间感到非常困惑,但它仅适用于 26+。然后说使用ThreeTen,后来它已经过时了。那么,你能告诉我我应该在 API 21 的项目中使用什么吗?谢谢!java.time
0赞 Basil Bourque 9/1/2021
@RawHasan 请参阅我对末尾“关于 java.time”部分的新编辑。(A) 对于 26 之前的 Android,我建议您先尝试最新 Android 工具中的“API 脱糖”功能。这为您提供了早期 Android 中的许多 java.time 功能。(B) 如果缺少您需要的某些功能,则回退到将 ThreeTenABP 库添加到您的项目中,这是 ThreeTen-Backport Java 库的 Android 特定改编版,该库也提供了大部分 java.time 功能。ThreeTen-Backport 库使用与 java.time 几乎相同的 API。
0赞 Raw Hasan 9/1/2021
谢谢,@Basil Bourque!我是一名新的 Kotlin 开发人员,所有这些日期时间的事情对我来说都变得非常困惑!但我想我终于想通了。我刚刚根据 Kael 的最新编辑设置了依赖项,看起来功能现在正在我的 21 API 项目上运行。java.time