ChatGPT解决这个技术问题 Extra ChatGPT

如何在 Android 项目中使用 ThreeTenABP

我问这个问题是因为我是 Java 和 Android 的新手,我搜索了几个小时试图弄清楚这一点。答案来自相关答案的组合,所以我想我会记录我所学到的知识,以供其他可能正在苦苦挣扎的人使用。见答案。

我正在使用 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)

k
kael

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

现在可通过 Android Gradle Plugin 4.0.0+ 获得 Java 8+ API 脱糖支持

(另见Basil Bourque's answer below

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

要在任何版本的 Android 平台上启用对这些语言 API 的支持,请更新 Android plugin to 4.0.0 (or higher) 并在模块的 build.gradle 文件中包含以下内容:

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 的实现,它是基于 Joda-Time 库的时间处理新标准提案。

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

下一个选项可能是 Joda-Time,因为 JSR 310 基于 Joda-Time。但是,正如 ThreeTenABP readme 所示,出于多种原因,Joda-Time 并不是最佳选择。

接下来是 ThreeTen-Backport,它将 Java 8 java.time 的大部分(但不是全部)功能向后移植到 Java 7。这对于大多数用例来说都很好,但是如 ThreeTenABP readme 所示,它存在性能问题与安卓。

所以最后一个看似正确的选项是 ThreeTenABP

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

由于编译程序(尤其是使用大量外部库的程序)很复杂,Java 几乎总是使用 "build tool" 来管理进程。 MakeApache AntApache MavenGradle 都是用于 Java 程序的构建工具(参见 this post 进行比较)。正如下文所述,Gradle 是 Android 项目的首选构建工具。

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

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

我的首要任务是阅读 Gradle 文档 here,包括他们的免费电子书。如果我在几周前开始学习 Android 时阅读了这些内容,我肯定会知道 Gradle 可以使用 Maven 中央存储库来管理 Android 项目中的依赖项。此外,如 this StackOverflow 回答中所述,从 Android Studio 0.8.9 开始,Gradle 通过 Bintray 的 JCenter 隐式使用 Maven Central Repository,这意味着您无需进行任何额外的配置来设置 repo——您只需列出依赖项。

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

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

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

还有一个问题我花了太多时间弄清楚。如果您在 Maven Central 中查找 ThreeTen,您只会看到 threetenbp 的包,而不是 threetenabp。如果您转到 github repo for ThreeTenABP,您会在自述文件的下载部分看到臭名昭著的 compile 'this-or-that' 行。

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

总结:让它发挥作用

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

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'
}

还要将此添加到应用程序类:

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

谢谢你的好帖子。但是,我想知道您是否也考虑过 JodaTimeAndroid
@Bob,我没有尝试过 JodaTimeAndroid,但这只是因为我现在并没有真正在做任何需要它的事情。据我记得,java.time 的实现很好(基本上是 JodaTime 的一个端口),而且我确信再过一两年,90% 的用户将使用 Nougat+,使其成为一个可行的开发解决方案。
@Bob,JodaTime 与 JSR-310 基本相同(甚至基本上是由同一个人制造的),除了 JSR-310 据称具有较少的设计缺陷(例如,参见 this article)。 [...继续下面]
为了澄清评论... java.time 框架 (JSR 310) 是 Joda-Time 项目的正式继承者。这两个项目都由同一个人领导,Stephen Colebourne。 Joda-Time 项目现在处于维护模式,团队建议迁移到 java.time。
确保在使用 API 之前调用 AndroidThreeTen.init(this),例如在 onCreate() 中。请参阅 ThreeTen-Backport error on Android - ZoneRulesException: No time-zone data files registered
B
Basil Bourque

接受的 Answer by kael 是正确的。另外,我会提到一些事情,并提供一个关于获取 java.time 功能的图表。

java.time 内置于 Android 26+

如果定位到 Android 26 或更高版本,您会发现与 Android 捆绑在一起的 JSR 310java.time 类)的实现。无需添加ThreeTenABP

API 几乎相同

澄清一下,适用于 Android 的 ThreeTenABP 是对 ThreeTen-Backport 库的改编,它为 Java 6Java 7 带来了大部分 java.time 功能。这个反向移植与 java.time 共享几乎相同的 API。

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

从 ThreeTenABP 到 java.time 的过渡过程应该是顺利且几乎无痛的。

何时使用哪个框架

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

➥ 更新: Android Gradle 插件 4.0.0+ 带来了新的第四个选项,API desugaring,以提供最初未内置于早期 Android 中的 subset of java.time functionality。请参阅 kael 的 main Answer 的顶部。

https://i.stack.imgur.com/Sksw9.png

关于 java.time

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

要了解更多信息,请参阅 Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310

Joda-Time 项目现在位于 maintenance mode 中,建议迁移到 java.time 类。

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

从哪里获得 java.time 类?

Java SE 8、Java SE 9、Java SE 10、Java SE 11 及更高版本 - 标准 Java API 的一部分,具有捆绑的实现。 Java 9 带来了一些小功能和修复。

Java 9 带来了一些小功能和修复。

Java SE 6 和 Java SE 7 大多数 java.time 功能在 ThreeTen-Backport 中向后移植到 Java 6 和 7。

大多数 java.time 功能在 ThreeTen-Backport 中向后移植到 Java 6 和 7。

Android 更高版本的 Android (26+) 捆绑了 java.time 类的实现。对于早期的 Android (<26),API 脱糖过程带来了最初未内置于 Android 中的 java.time 功能的子集。如果脱糖不能提供您所需要的,ThreeTenABP 项目会将 ThreeTen-Backport(上面提到的)适配到 Android。请参阅如何使用 ThreeTenABP……。

更高版本的 Android (26+) 捆绑了 java.time 类的实现。

对于早期的 Android (<26),API 脱糖过程带来了最初未内置于 Android 中的 java.time 功能的子集。如果脱糖不能提供您所需要的,ThreeTenABP 项目会将 ThreeTen-Backport(上面提到的)适配到 Android。请参阅如何使用 ThreeTenABP……。

如果脱糖不能提供您所需要的,ThreeTenABP 项目会将 ThreeTen-Backport(上面提到的)适配到 Android。请参阅如何使用 ThreeTenABP……。


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

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

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

创建 Application 类并像这样初始化它:

class App : Application() {
    override fun onCreate() {
        super.onCreate()
        AndroidThreeTen.init(this)
    }
}