Android Studio w wersji 4.0 wprowadza bardzo wyczekiwaną przeze mnie funkcjonalność, ponieważ pomimo wprowadzenia możliwości korzystania z Javy 8, obsługa tej wersji języka była bardzo mocno ograniczona. Jedną z nowości było wprowadzenie w Javie 8 przeprojektowanego API obsługi daty i czasu, które nie było dostępne dla każdego w Androidzie.
Kto pisał aplikacje na system operacyjny Android z obsługą operacji na dacie i czasie, wie, że nie jest to najprostsze i najwygodniejsze zadanie. Wprowadzenie obsługi Java 8 do Androida niestety nie pomogło w zupełności, pomimo tego, że ta wersja języka wprowadza zaprojektowane na nowo API do obsługi daty i czasu, było ono dostępne od Android SDK 26, więc aplikacja musiałaby wspierać minimum Androida w wersji 8.0. Korzystanie z Kotlina zamiast Javy również nie rozwiązywało problemu, ponieważ Kotlin nie posiada swojego API do realizacji tych zadań. Najlepszym wyjściem z tej sytuacji było skorzystanie z biblioteki Joda-Time, która oferuje API, które jest zamiennikiem do API Javy.
Teraz jest jeszcze jeden sposób na rozwiązanie tego problemu. Wraz z premierą Android Studio 4.0, została wydana nowa wersja pluginu Gradle Androida w wersji 4.0.0, która umożliwia skorzystanie z nowych API Javy 8 również w starszych wersjach systemu Android przy pomocy biblioteki służącej do desugaryzacji (zamianie ładnego, czytelnego kodu dla programisty na kod zrozumiały dla kompilatora).
Konfiguracja projektu
Aby skorzystać z nowego rozwiązania, należy wprowadzić kilka modyfikacji do projektu. Zmiany należy zastosować w pliku build.gradle swojego modułu:
android {
defaultConfig {
// wymagane dla minSdkVersion 20 lub niższej
multiDexEnabled true
}
compileOptions {
// flaga ustawiająca obsługę nowych API języka
coreLibraryDesugaringEnabled true
// włączenie kompatybilności z Javą 8
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.0.5'
}
Jak widać powyżej, konfiguracja projektu nie jest wcale skomplikowana, a może przynieść nam sporo ułatwień podczas prac nad aplikacjami.
W praktyce całość ogranicza się do ustawienia flagi coreLibraryDesugaringEnabled, instalacji biblioteki do desugaryzacji oraz włączenia kompatybilności z Javą 8 (jak było to robione do tej pory).
LocalDate
Obiekt tej klasy jest przeznaczony do przechowywania informacji o dacie bez informacji o strefie czasowej. Obiekt tej klasy możemy stworzyć w następujący sposób:
LocalDate.now()- aktualna dataLocalDate.parse(String date)- obiekt na podstawie daty w formacie ISOLocalDate.of(int year, int month, int day)- obiekt na podstawie liczbowej prezentacji rok-miesiąc-dzień
Przykład w języku Kotlin:
val localDateNow = LocalDate.now()
Log.i("TAG_DATE", localDateNow.toString())
val localDateParse = LocalDate.parse("2020-06-01")
Log.i("TAG_DATE", localDateParse.toString())
val localDateOf = LocalDate.of(2020, 6, 1)
Log.i("TAG_DATE", localDateOf.toString())
LocalTime
Klasa ta służy do przechowywania informacji o samym czasie bez informacji o strefie czasowej. Obiekt tej klasy możemy stworzyć w następujący sposób:
LocalTime.now()- aktualny czasLocalTime.parse(String time)- obiekt na podstawie czasu w formacie ISOLocalTime.of(int hour, int minute, int second, int nanoOfSecond)(obowiązkowe jest tylko podanie godziny oraz minuty) - obiekt na podstawie liczbowej prezentacji godzina-minuta-sekunda-nanosekunda
Przykład w języku Kotlin:
val localTimeNow = LocalTime.now()
Log.i("TAG_TIME", localTimeNow.toString())
val localTimeParse = LocalTime.parse("15:30:20")
Log.i("TAG_TIME", localTimeParse.toString())
val localTimeOf = LocalTime.of(15, 30, 20)
Log.i("TAG_TIME", localTimeOf.toString())
LocalDateTime
Ta klasa służy do przechowywania daty oraz czasu w jednym obiekcie. Również ona, tak jak dwie poprzednie, nie przechowuje informacji o strefie czasowej. Obiekty tej klasy można stworzyć w następujący sposób:
LocalDateTime.now()- aktualny czasLocalDateTime.parse(String time)- obiekt na podstawie czasu w formacie ISOLocalDateTime.of(int year, int month, int day, int hour, int minute, int second, int nanoOfSecond)(obowiązkowe jest podanie roku, miesiąca, dnia oraz godziny i minuty) - obiekt na podstawie liczbowej prezentacji godzina-minuta-sekunda-nanosekundaLocalDateTime.of(LocalDate date, LocalTime time)- na podstawie obiektów klasLocalDateorazLocalTime
Przykład w języku Kotlin:
val localDateTimeNow = LocalDateTime.now()
Log.i("TAG_DATE_TIME", localDateTimeNow.toString())
val localDateTimeParse = LocalDateTime.parse("2020-06-01T15:30:20")
Log.i("TAG_DATE_TIME", localDateTimeParse.toString())
val localDateTimeOf = LocalDateTime.of(2020, 6, 1, 15, 30, 20)
Log.i("TAG_DATE_TIME", localDateTimeOf.toString())
val localDateTimeOfLocal = LocalDateTime.of(LocalDate.now(), LocalTime.now())
Log.i("TAG_DATE_TIME", localDateTimeOfLocal.toString())
Modyfikacja daty i czasu
Nowe API dostarcza bardzo proste metody służące do modyfikacji zapisanych informacji. Z niebywałą łatwością jesteśmy w stanie dodawać czy odejmować konkretny okres czasu.
Podczas tych operacji warto pamiętać, że daty w nowym API są niezmienne w związku z czym metody modyfikujące datę i czas zwracają nową instancję, nie modyfikując istniejącej.
Do modyfikacji dat możemy wykorzystać metody:
LocaleDate.plusDays(long daysToAdd)lubLocaleDateTime.plusDays(long daysToAdd)- dodanie określonej ilości dniLocaleDate.plusWeeks(long weeksToAdd)lubLocaleDateTime.plusWeeks(long weeksToAdd)- dodanie określonej ilości tygodniLocaleDate.plusMonths(long monthsToAdd)lubLocaleDateTime.plusMonths(long monthsToAdd)- dodanie określonej ilości miesięcyLocaleDate.plusYears(long yearsToAdd)lubLocaleDateTime.plusYears(long yearsToAdd)- dodanie określonej ilości latLocaleDate.minusDays(long daysToSubtract)lubLocaleDateTime.minusDays(long daysToSubtract)- odjęcie określonej ilości dniLocaleDate.minusWeeks(long weeksToSubtract)lubLocaleDateTime.minusWeeks(long weeksToSubtract)- odjęcie określonej ilości tygodniLocaleDate.minusMonths(long monthsToSubtract)lubLocaleDateTime.minusMonths(long monthsToSubtract)- odjęcie określonej ilości miesięcyLocaleDate.minusYears(long yearsToSubtract)lubLocaleDateTime.minusYears(long yearsToSubtract)- odjęcie określonej ilości lat
Przykład w języku Kotlin:
val localDate = LocalDate.now()
Log.i("TAG_MODIFY", "Obecna data: $localDate")
val tomorrowDate = localDate.plusDays(1)
Log.i("TAG_MODIFY", "Jutrzejsza data: $tomorrowDate")
val date3MonthsBefore = localDate.minusMonths(3)
Log.i("TAG_MODIFY", "Data sprzed 3 miesięcy: $date3MonthsBefore")
Do modyfikacji czasu możemy wykorzystać metody:
LocalTime.plusHours(long hoursToAdd)lubLocalDateTime.plusHours(long hoursToAdd)- dodanie określonej ilości godzinLocalTime.plusMinutes(long minutesToAdd)lubLocalDateTime.plusMinutes(long minutesToAdd)- dodanie określonej ilości minutLocalTime.plusSeconds(long secondstoAdd)lubLocalDateTime.plusSeconds(long secondstoAdd)- dodanie określonej ilości sekund-
LocalTime.plusNanos(long nanosToAdd)lubLocalDateTime.plusNanos(long nanosToAdd)- dodanie określonej ilości nanosekund LocalTime.minusHours(long hoursToSubtract)lubLocalDateTime.minusHours(long hoursToSubtract)- odjęcie określonej ilości godzinLocalTime.minusMinutes(long minutesToSubtract)lubLocalDateTime.minusMinutes(long minutesToSubtract)- odjęcie określonej ilości minutLocalTime.minusSeconds(long secondsToSubtract)lubLocalDateTime.minusSeconds(long secondsToSubtract)- odjęcie określonej ilości sekundLocalTime.minusNanos(long nanosToSubtract)lubLocalDateTime.minusNanos(long nanosToSubtract)- odjęcie określonej ilości nanosekund
Przykład w języku Kotlin:
val localTime = LocalTime.now()
Log.i("TAG_MODIFY", "Obecny czas: $localTime")
val time4HoursAfter = localTime.plusHours(4)
Log.i("TAG_MODIFY", "Czas za 4 godziny: $time4HoursAfter")
val time500SecondsBefore = localTime.minusSeconds(500)
Log.i("TAG_MODIFY", "Czas sprzed 500 sekund: $time500SecondsBefore")
Formatowanie daty i czasu
Nowe API daty i czasu wprowadza również nową klasę służącą za formatowanie. Dzięki niej możemy sformatować datę i czas do określonego formatu jako tekst, jak również z niestandardowego formatu tekstu na odpowiedni obiekt:
val localDateTime = LocalDateTime.now()
val dateTimeFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss")
val stringFromDateTime = dateTimeFormatter.format(localDateTime)
Log.i("TAG_FORMAT", "Data i czas sformatowane do stringa: $stringFromDateTime")
val dateTimeFromString = LocalDateTime.parse("01.06.2020 15:30:20", dateTimeFormatter)
Log.i("TAG_FORMAT", "Data i czas ze stringa: $dateTimeFromString")
Porównywanie dat
Dzięki nowemu API również w łatwy sposób możemy porównywać ze sobą dwie daty, aby sprawdzić, czy nie są równie lub któraś z nich jest późniejsza. Możemy skorzystać z następujących metod:
date1.isAfter(date2)- data, na której wywołujemy metodę, jest po dacie z parametrudate1.isBefore(date2)- data, na której wywołujemy metodę, jest przed datą z parametrudate1.isEqual(date2)- data, na której wywołujemy metodę, jest równa dacie z parametrudate1.compareTo(date2)- większe od 0 - odpowiednikisAfter(), mniejsze od 0 - odpowiednikisBefore(), równe 0 - odpowiednikisEqual()
A to jest przykład w języku Kotlin:
val localDate1 = LocalDate.of(2020, 6, 1)
val localDate2 = LocalDate.of(2020, 5, 1)
val isAfter = localDate1.isAfter(localDate2)
Log.i("TAG_COMPARE", "Czy pierwsza data jest po drugiej: $isAfter")
val isBefore = localDate1.isBefore(localDate2)
Log.i("TAG_COMPARE", "Czy pierwsza data jest przed drugą: $isBefore")
val isEqual = localDate1.isEqual(localDate2)
Log.i("TAG_COMPARE", "Czy obie daty są równe: $isEqual")
val compareTo = localDate1.compareTo(localDate2)
when {
compareTo > 0 -> {
Log.i("TAG_COMPARE", "Pierwsza data jest po drugiej dacie")
}
compareTo < 0 -> {
Log.i("TAG_COMPARE", "Pierwsza data jest przed drugą datą")
}
compareTo == 0 -> {
Log.i("TAG_COMPARE", "Obie daty są równe")
}
}
Podsumowanie
Ten wpis nie wyczerpuje tematu związanego z nowym API Javy 8 do daty i czasu, które właśnie stało się szeroko dostępne w systemie Android. Dostępne są również inne nowe klasy służące do pracy z datą i czasem jak na przykład Period, która odpowiada za reprezentację okresu pomiędzy datami, jak również ZonedDateTime, która jest odpowiednikiem LocalDateTime jednak przechowującą również informację na temat strefy czasowej. Po bardziej szczegółowe informacje odsyłam do dokumentacji języka Java.
Jak widać, nowe API jest bardzo pomocne i zdecydowanie ułatwia pracę z datą i czasem w trakcie pisania aplikacji na system Android. Szkoda tylko, że trzeba było czekać na nie aż ponad 6 lat, od daty wydania Javy 8.