如何在 Android 项目中使用 ThreeTenABP

How to use ThreeTenABP in Android Project

我问这个问题是因为我是 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)

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

Java 8+ API 脱糖支持现在可通过 Android Gradle 插件 4.0.0+

获得

(另见

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.timeThreeTen-Backport ,甚至 Joda-Time

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

最明显的解决方案是使用内置的 java.time package, since this is the new standard way to deal with time and dates in Java. It is an implementation of JSR 310, which was a new standard proposal for time handling based on the Joda-Time 库。

然而,java.time 是在 Java 8. Android up to Marshmallow runs on Java 7 ("Android N" is the first version to introduce Java 8 language features). Thus, unless you're only targeting Android N Nougat 及更高版本中引入的,你不能依赖 Java 8 种语言功能(我实际上不确定这是 100% 正确的,但这就是我的理解)。所以 java.time 出局了。

下一个选项可能是 Joda-Time, since JSR 310 was based on Joda-Time. However, as the ThreeTenABP readme 表明,出于多种原因,Joda-Time 不是最佳选择。

下一个是 ThreeTen-Backport, which back-ports much (but not all) of the Java 8 java.time functionality to Java 7. This is fine for most use cases, but, as indicated in the ThreeTenABP readme,Android 有性能问题。

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

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

由于编译一个程序——尤其是使用一堆外部库的程序——很复杂,Java 几乎总是使用 "build tool" to manage the process. Make, Apache Ant, Apache Maven, and Gradle are all build tools that are used with Java programs (see this post 进行比较)。如下所述,Gradle 是 Android 项目选择的构建工具。

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

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

在我的待办事项列表中排在首位的是阅读 Gradle 文档 here, including their free eBooks. Had I read these weeks ago when I started learning Android, I would surely have known that Gradle can use the Maven Central Repository to manage dependencies in Android Projects. Furthermore, as detailed in this Whosebug 答案,从 Android Studio 0.8.9 开始,Gradle 使用 Maven Central通过 Bintray 的 JCenter 隐式存储库,这意味着您无需执行任何额外的配置来设置存储库——您只需列出依赖项。

第四个发现:项目依赖项列在[项目目录]/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 存储库时,我不知道那条编译行是什么意思,我试图在我的终端中 运行 它(有一个明显且可预见的失败)。沮丧的是,直到我弄清楚其余部分后很久我才 return 它,并最终意识到这是指向 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'
}

同时将此添加到应用程序 class:

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

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

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

创建应用程序 class 并像这样初始化它:

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

接受的是正确的。此外,我将提及几件事,并提供有关获取 java.time 功能的图表。

java.time 内置于 Android 26+

如果定位 Android 26 or later, you will find an implementation of JSR 310java.time 类)与 Android 捆绑在一起。无需添加 ThreeTenABP.

API几乎相同

澄清一下,ThreeTenABP for Android is an adaptation of the ThreeTen-Backport library that brings most of the java.time functionality to Java 6 and Java 7。此反向端口与 java.time.

共享几乎相同的 API

假设您现在的目标 Android 早于 26,因此您使用 ThreeTenABP。稍后,您可能最终会放弃对这些早期版本 Android 的支持,以使用与 Android 捆绑在一起的 java.time 类。发生这种情况时,除了 (a) 切换 import 语句和 (b) 更改对 org.threeten.bp.DateTimeUtils 的任何调用以使用添加到旧的遗留日期时间 类 (Date, GregorianCalendar).

ThreeTenABPjava.time的过渡过程应该很顺利,几乎没有痛苦。

何时使用哪个框架

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

➥ 更新: Android Gradle 插件 4.0.0+ 带来了新的第四个选项,API desugaring to make available a subset of java.time functionality not originally built into earlier Android. See the top of the by kael.


关于java.time

java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

要了解更多信息,请参阅 Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310

Joda-Time project, now in maintenance mode, advises migration to the java.time 类.

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

在哪里获取 java.time 类?