Jak korzystać z ThreeTenABP w Android Project

Aug 12 2016

Zadaję to pytanie, ponieważ jestem nowy w Javie i Androidzie i szukałem godzin, próbując to rozgryźć. Odpowiedź pochodziła z kombinacji powiązanych odpowiedzi, więc pomyślałem, że udokumentuję to, czego się nauczyłem, dla każdego, kto może mieć problemy. Zobacz odpowiedź.

Używam Android Studio 2.1.2, a moja konfiguracja Java wygląda następująco:

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

Odpowiedzi

200 kael Aug 12 2016 at 23:36

Uwaga: ta odpowiedź, chociaż technicznie poprawna, jest obecnie nieaktualna

Obsługa desugowania Java 8+ API jest teraz dostępna za pośrednictwem wtyczki Android Gradle 4.0.0+

(Zobacz również odpowiedź Basil Bourque poniżej )

Rozwój biblioteki ThreeTenABP dobiega końca . Proszę rozważyć przejście na wtyczkę Android Gradle 4.0, java.time. * I funkcję usuwania cugry z podstawowej biblioteki w nadchodzących miesiącach.

Aby włączyć obsługę tych językowych interfejsów API w dowolnej wersji platformy Android, zaktualizuj wtyczkę systemu Android do wersji 4.0.0 (lub nowszej) i dołącz następujące elementy do pliku build.gradle modułu:

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

Oryginalna odpowiedź

Pierwsze odkrycie: dlaczego musisz używać ThreeTenABP zamiast java.time , ThreeTen-Backport , a nawet Joda-Time

To jest naprawdę krótka wersja BARDZO DŁUGIEGO PROCESU definiowania nowego standardu. Wszystkie te pakiety to prawie to samo: biblioteki, które zapewniają dobrą, nowoczesną obsługę języka Java. Różnice są subtelne, ale ważne.

Najbardziej oczywistym rozwiązaniem byłoby użycie wbudowanego java.timepakietu, ponieważ jest to nowy standardowy sposób radzenia sobie z czasem i datami w Javie. Jest to implementacja JSR 310 , która była nową standardową propozycją obsługi czasu opartą o bibliotekę Joda-Time .

Jednak java.timezostał wprowadzony w Javie 8 . Android do Marshmallow działa na Javie 7 („Android N” jest pierwszą wersją, która wprowadza funkcje językowe Java 8). Tak więc, jeśli nie celujesz tylko w system Android N Nougat i nowszy, nie możesz polegać na funkcjach językowych Java 8 (nie jestem pewien, czy to w 100% prawda, ale tak to rozumiem). Więc java.timejest na zewnątrz.

Następną opcją może być Joda-Time , ponieważ JSR 310 był oparty na Joda-Time. Jednak, jak wskazuje plik Readme ThreeTenABP , z wielu powodów Joda-Time nie jest najlepszą opcją.

Następny jest ThreeTen-Backport , który przenosi wiele (ale nie wszystkie) funkcjonalności Java 8 java.timedo Java 7. Jest to w porządku w większości przypadków użycia, ale, jak wskazano w pliku Readme ThreeTenABP , ma problemy z wydajnością w systemie Android.

Więc ostatnią i pozornie poprawną opcją jest ThreeTenABP .

Drugie odkrycie: narzędzia budowania i zarządzanie zależnościami

Ponieważ kompilowanie programu - zwłaszcza takiego, który wykorzystuje kilka bibliotek zewnętrznych - jest skomplikowane, Java prawie zawsze używa „narzędzia do budowania” do zarządzania tym procesem. Make , Apache Ant , Apache Maven i Gradle to narzędzia do budowania, które są używane z programami Java (zobacz ten post w celu porównania). Jak wspomniano poniżej, Gradle jest wybranym narzędziem do kompilacji projektów dla systemu Android.

Te narzędzia do kompilacji obejmują zarządzanie zależnościami. Wydaje się, że Apache Maven jako pierwszy zawiera scentralizowane repozytorium pakietów. Maven wprowadził Maven Central Repository , które zapewnia funkcjonalność równoważną php composerz Packagist i Ruby's gemz rubygems.org. Innymi słowy, Maven Central Repository jest dla Mavena (i Gradle'a) tym, czym Packagist dla kompozytora - ostatecznym i bezpiecznym źródłem pakietów wersjonowanych.

Trzecie odkrycie: Gradle obsługuje zależności w projektach systemu Android

Wysoko na mojej liście rzeczy do zrobienia jest, aby przeczytać Gradle docs tutaj , w tym ich książek gratis. Gdybym czytał kilka tygodni temu, kiedy zacząłem uczyć się Androida, z pewnością wiedziałbym, że Gradle może używać Maven Central Repository do zarządzania zależnościami w projektach Androida. Ponadto, jak opisano szczegółowo w tej odpowiedzi StackOverflow, od wersji Android Studio 0.8.9, Gradle używa Maven Central Repository niejawnie za pośrednictwem JCenter Bintray, co oznacza, że ​​nie musisz wykonywać żadnej dodatkowej konfiguracji, aby skonfigurować repozytorium - wystarczy wymienić zależności.

Czwarte odkrycie: Zależności projektu są wymienione w [katalog projektu] /app/build.gradle

Ponownie, oczywiste dla tych, którzy mają jakiekolwiek doświadczenie w używaniu Gradle w Javie, ale zajęło mi trochę czasu, zanim to zrozumiałem. Jeśli zobaczysz, że ludzie mówią „Och, po prostu dodaj compile 'this-or-that.jar'” lub coś podobnego, wiedz, że compilejest to dyrektywa w tym pliku build.gradle, która wskazuje na zależności w czasie kompilacji. Oto oficjalna strona Gradle dotycząca zarządzania zależnościami.

Piąte odkrycie: ThreeTenABP jest zarządzane przez Jake'a Whartona, a nie przez ThreeTen

Kolejna kwestia, nad którą spędziłem zbyt dużo czasu, zastanawiała się. Jeśli szukasz ThreeTen w Maven Central, zobaczysz tylko pakiety threetenbp, a nie threetenabp. Jeśli przejdziesz do repozytorium ThreeTenABP na githubie , zobaczysz ten niesławny compile 'this-or-that'wiersz w sekcji pobierania pliku Readme.

Kiedy po raz pierwszy trafiłem na to repozytorium github, nie wiedziałem, co oznacza ten wiersz kompilacji, i próbowałem go uruchomić na moim terminalu (z oczywistą i przewidywalną awarią). Sfrustrowany, wróciłem do tego dopiero długo po tym, jak wymyśliłem resztę i w końcu zdałem sobie sprawę, że to linia Maven Repo wskazująca na com.jakewharton.threetenabprepozytorium, a nie org.threetenrepozytorium. Dlatego pomyślałem, że pakiet ThreeTenABP nie znajduje się w repozytorium Maven.

Podsumowanie: Jak to działa

Teraz wszystko wydaje się całkiem proste. Możesz uzyskać nowoczesne funkcje obsługi czasu w projekcie systemu Android, upewniając się, że [project folder]/app/build.gradleplik ma implementation 'com.jakewharton.threetenabp:threetenabp:1.2.1'linię w dependenciessekcji:

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

Dodaj to również do klasy Application:

public class App extends Application {    
    @Override
    public void onCreate() {
        super.onCreate();
        AndroidThreeTen.init(this);
        //...
    }
}
8 BasilBourque May 05 2020 at 07:35

Przyjęta odpowiedź przez kael jest poprawna. Ponadto wspomnę o kilku rzeczach i przedstawię diagram dotyczący uzyskiwania funkcjonalności java.time .

java.time wbudowany w Androida 26+

W przypadku systemu Android 26 lub nowszego znajdziesz implementację JSR 310 ( klasy java.time ) w pakiecie z systemem Android. Nie ma potrzeby dodawania ThreeTenABP .

API prawie identyczne

Gwoli wyjaśnienia, ThreeTenABP na Androida to adaptacja biblioteki ThreeTen-Backport, która przenosi większość funkcji java.time do Java 6 i Java 7 . Ten tylny port ma prawie identyczny interfejs API z java.time .

Załóżmy, że celujesz teraz w system Android starszy niż 26 lat, więc używasz ThreeTenABP . Później możesz ostatecznie zrezygnować z obsługi tych wcześniejszych wersji Androida, aby korzystać z klas java.time dołączonych do Androida. Kiedy tak się stanie, musisz wprowadzić kilka zmian w bazie kodu innych niż (a) importinstrukcje przełączania i (b) zmiana wszelkich wywołań, które wykonałeś, org.threeten.bp.DateTimeUtilsaby użyć nowych metod konwersji, które zostały dodane do starych klas daty i godziny ( Date, GregorianCalendar) .

Proces przejścia z ThreeTenABP do java.time powinien być płynny i prawie bezbolesny.

Kiedy używać którego frameworka

Oto wykres przedstawiający trzy struktury i wskazujący, kiedy użyć której z nich, w jakich scenariuszach.

➥ Aktualizacja: wtyczka Android Gradle 4.0.0+ wprowadza nową czwartą opcję, desugering API, aby udostępnić podzbiór funkcji java.time, które nie były pierwotnie wbudowane we wcześniejszy system Android. Zobacz górę głównej odpowiedzi kaela.


Informacje o java.time

Struktura java.time jest wbudowana w Javę 8 i nowsze. Klasy te kłopotliwe zastąpić stary starszych klas Date-Time, takich jak java.util.Date, Calendar, i SimpleDateFormat.

Aby dowiedzieć się więcej, zobacz samouczek Oracle . I przeszukaj Stack Overflow, aby znaleźć wiele przykładów i wyjaśnień. Specyfikacja to JSR 310 .

Projekt Joda-Time , obecnie w trybie konserwacji , zaleca migrację do klas java.time .

Możesz wymieniać obiekty java.time bezpośrednio ze swoją bazą danych. Użyj sterownika JDBC zgodnego z JDBC 4.2 lub nowszym. Nie ma potrzeby stosowania ciągów ani java.sql.*klas. Hibernate 5 i JPA 2.2 obsługują java.time .

Skąd wziąć klasy java.time?

5 RichardKamere Aug 19 2019 at 00:02

Dodaj następujące elementy w pliku gradle kompilacji w Android Studio.

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

Utwórz klasę Application i zainicjuj ją w następujący sposób:

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