Poziom API: 19
Android 4.4 (KITKAT
) to nowa wersja platformy Android, która zawiera nowe funkcje dla użytkowników i programistów aplikacji. Ten dokument zawiera wprowadzenie do najważniejszych nowych interfejsów API.
Jako deweloper aplikacji jak najszybciej pobierz obraz systemu Android 4.4 i platformę SDK z Menedżera pakietu SDK. Jeśli nie masz urządzenia z Androidem 4.4, na którym możesz przetestować aplikację, użyj obrazu systemu Android 4.4, aby przetestować aplikację na emulatorze Androida. Następnie utwórz aplikacje na platformę Android 4.4, aby zacząć korzystać z najnowszych interfejsów API.
Zaktualizuj docelowy poziom interfejsu API
Aby lepiej zoptymalizować aplikację na urządzenia z Androidem 4.4, ustaw targetSdkVersion
na "19"
, zainstaluj ją na obrazie systemu Androida 4.4, przetestuj ją, a następnie opublikuj aktualizację z tą zmianą.
Możesz używać interfejsów API w Androidzie 4.4, a zarazem obsługiwać starsze wersje, dodając do kodu warunki, które sprawdzają poziom interfejsu API systemu przed wykonaniem interfejsów API nieobsługiwanych przez minSdkVersion
.
Więcej informacji o utrzymywaniu zgodności wstecznej znajdziesz w artykule Obsługa różnych wersji platform.
Więcej informacji o tym, jak działają poziomy interfejsu API, znajdziesz w artykule Co to jest poziom interfejsu API?
Ważne zmiany w działaniu
Jeśli aplikacja na Androida została już opublikowana, zmiany w Androidzie 4.4 mogą mieć na nią wpływ.
Jeśli aplikacja odczytuje dane z pamięci zewnętrznej…
Aplikacja nie może odczytywać udostępnionych plików na zewnętrznym urządzeniu pamięci masowej, jeśli działa na Androidzie 4.4, chyba że ma uprawnienia READ_EXTERNAL_STORAGE
. Oznacza to, że pliki w katalogu zwróconym przez getExternalStoragePublicDirectory()
nie są już dostępne bez uprawnień. Jeśli jednak potrzebujesz dostępu tylko do katalogów aplikacji udostępnianych przez getExternalFilesDir()
, nie musisz mieć uprawnień READ_EXTERNAL_STORAGE
.
Jeśli Twoja aplikacja korzysta z komponentu WebView…
Aplikacja może zachowywać się inaczej na Androidzie 4.4, zwłaszcza gdy zaktualizujesz wartość targetSdkVersion
na „19” lub wyższą.
Kod leżący u podstaw klasy WebView
i powiązanych interfejsów API został ulepszony i oparty na nowoczesnym zrzucie kodu źródłowego Chromium. Dzięki temu możesz liczyć na liczne ulepszenia wydajności, obsługę nowych funkcji HTML5 oraz debugowanie zdalne treści WebView
. Zakres tego uaktualnienia oznacza, że jeśli Twoja aplikacja korzysta z funkcji WebView
, w niektórych przypadkach może to wpłynąć na jej działanie. Chociaż znane zmiany zachowania są udokumentowane i w większości przypadków wpływają na Twoją aplikację tylko wtedy, gdy zaktualizujesz targetSdkVersion
do wersji „19” lub nowszej, nowy interfejs WebView
działa w „trybie obsługi starszych wersji”, aby zapewniać niektóre starsze funkcje w aplikacjach kierowanych na poziom interfejsu API 18 i starsze. Możliwe, że Twoja aplikacja zależy od nieznanych zachowań z poprzedniej wersji interfejsu WebView
.
Jeśli Twoja obecna aplikacja korzysta z WebView
, jak najszybciej przetestuj ją na Androidzie 4.4 i przeczytaj artykuł Przejście na WebView w Androidzie 4.4, aby dowiedzieć się, jak może to wpłynąć na Twoją aplikację po zaktualizowaniu targetSdkVersion
do wersji „19” lub nowszej.
Jeśli Twoja aplikacja używa AlarmManagera…
Jeśli ustawisz wartość parametru targetSdkVersion
w aplikacji na „19” lub wyższą, alarmy utworzone za pomocą funkcji set()
lub setRepeating()
będą niedokładne.
Aby zwiększyć oszczędność energii, Android łączy teraz alarmy ze wszystkich aplikacji, które występują w zbliżonym czasie, dzięki czemu system wybudza urządzenie raz, a nie kilka razy, aby obsłużyć każdy alarm.
Jeśli alarm nie jest powiązany z dokładną godziną, ale zależy Ci, aby był wywoływany w określonym przedziale czasu (np. między 14:00 a 16:00), możesz użyć nowej metody setWindow()
, która przyjmuje „najwcześniejszy” czas alarmu i „okno” czasowe poprzedzające najwcześniejszy czas, w którym system powinien wywołać alarm.
Jeśli alarm musi być przypięty do dokładnej godziny (np. w przypomnieniu o wydarzeniu w kalendarzu), możesz użyć nowej metody setExact()
.
To nieprecyzyjne grupowanie dotyczy tylko zaktualizowanych aplikacji. Jeśli ustawisz wartość targetSdkVersion
na „18” lub niższą, alarmy będą działać tak samo jak w poprzednich wersjach Androida 4.4.
Jeśli aplikacja synchronizuje dane za pomocą ContentResolver:
Gdy ustawisz wartość parametru targetSdkVersion
w aplikacji na „19” lub wyższą, utworzenie synchronizacji za pomocą parametru addPeriodicSync()
spowoduje wykonanie operacji synchronizacji w ramach domyślnego przedziału czasowego o długości około 4% podanego przez Ciebie okresu. Jeśli na przykład częstotliwość odpytywania wynosi 24 godziny, operacja synchronizacji może być wykonywana w ciągu dnia w przybliżeniu co godzinę, a nie o tej samej porze.
Aby określić własny przedział elastyczny dla operacji synchronizacji, zacznij używać nowej metody requestSync()
. Więcej informacji znajdziesz w sekcji poniżej dotyczącej adapterów synchronizacji.
To zachowanie interwału elastycznego dotyczy tylko zaktualizowanych aplikacji. Jeśli ustawienie targetSdkVersion
to „18” lub niższe, istniejące żądania synchronizacji będą działać tak samo jak w poprzednich wersjach na Androidzie 4.4.
Platforma drukowania
Android zawiera teraz kompletną platformę, która umożliwia użytkownikom drukowanie dowolnych dokumentów za pomocą drukarki połączonej przez Wi-Fi, Bluetooth lub inne usługi. System obsługuje transakcję między aplikacją, która chce wydrukować dokument, a usługami, które dostarczają zadania drukowania do drukarki. Platforma android.print
udostępnia wszystkie interfejsy API potrzebne do określenia dokumentu do wydrukowania i przekazania go do systemu w celu wydrukowania. Których interfejsów API potrzebujesz do danego zadania drukowania, zależy od treści.
Drukowanie treści ogólnych
Jeśli chcesz wydrukować zawartość interfejsu jako dokument, musisz najpierw utworzyć podklasę PrintDocumentAdapter
. W ramach tej klasy musisz zaimplementować kilka metod wywołania, w tym onLayout()
, aby określić układ na podstawie podanych właściwości drukowania, oraz onWrite()
, aby zakodować sekwencyjnie treści do drukowania w obiekcie ParcelFileDescriptor
.
Aby zapisać treści w ParcelFileDescriptor
, musisz je przesłać w formacie PDF. Nowe interfejsy API PdfDocument
umożliwiają wygodne tworzenie Canvas
z getCanvas()
, na którym możesz rysować treści do wydruku. Następnie zapisz PdfDocument
w ParcelFileDescriptor
, używając metody writeTo()
.
Po zdefiniowaniu implementacji PrintDocumentAdapter
możesz wykonywać zadania drukowania na żądanie użytkownika za pomocą metody PrintManager
, print()
, która przyjmuje jako jeden z argumentów wartość PrintDocumentAdapter
.
Drukowanie obrazów
Jeśli chcesz wydrukować tylko zdjęcie lub inną mapę bitową, pomocne będą interfejsy API w bibliotece pomocniczej. Wystarczy utworzyć nową instancję funkcji PrintHelper
, ustawić tryb skalowania za pomocą funkcji setScaleMode()
, a potem przekazać obiekt Bitmap
do funkcji printBitmap()
. To wszystko. Biblioteka obsługuje wszystkie pozostałe interakcje z systemem, aby przesłać bitmapę do drukarki.
Tworzenie usług drukowania
Jako producent OEM drukarki możesz korzystać z ramy android.printservice
, aby zapewnić interoperacyjność drukarek z urządzeniami z Androidem. Możesz tworzyć i rozpowszechniać usługi drukowania w formie plików APK, które użytkownicy mogą instalować na swoich urządzeniach . Aplikacja usługi drukowania działa głównie jako usługa bez interfejsu graficznego, ponieważ jest podklasą klasy PrintService
, która odbiera zadania drukowania z systemu i przekazuje je do drukarek za pomocą odpowiednich protokołów.
Więcej informacji o drukowaniu treści aplikacji znajdziesz w artykule Drukowanie treści.
Dostawca SMS-ów
Dostawca treści Telephony
(„Dostawca SMS-ów”) zezwala aplikacjom na odczyt i zapisywanie SMS-ów i MMS-ów na urządzeniu. Obejmuje ona tabele z danymi o SMS-ach i MMS-ach (otrzymanych, w komponowaniu, wysłanych, oczekujących itd.).
Od wersji 4.4 Androida użytkownicy mogą w ustawieniach systemu wybrać „domyślną aplikację do obsługi SMS-ów”. Po wybraniu tylko domyślna aplikacja do obsługi SMS-ów może zapisywać dane w usługodawcy SMS-ów i tylko domyślna aplikacja do obsługi SMS-ów może odbierać transmisję SMS_DELIVER_ACTION
, gdy użytkownik otrzyma SMS-a, lub transmisję WAP_PUSH_DELIVER_ACTION
, gdy użytkownik otrzyma MMS-a. Domyślna aplikacja do obsługi SMS-ów odpowiada za zapisywanie szczegółów w dostawcy SMS-ów, gdy odbiera lub wysyła nową wiadomość.
Inne aplikacje, które nie zostały wybrane jako domyślna aplikacja do obsługi SMS-ów, mogą tylko odczytywać dane z usługi SMS, ale mogą też otrzymywać powiadomienia o przybyciu nowego SMS-a, gdy odsłuchują transmisję SMS_RECEIVED_ACTION
, czyli nieprzerywalną transmisję, która może być wysyłana do wielu aplikacji. Ta transmisja jest przeznaczona dla aplikacji, które – mimo że nie są wybrane jako domyślna aplikacja do obsługi SMS-ów – muszą odczytywać specjalne wiadomości przychodzące, np. w celu weryfikacji numeru telefonu.
Więcej informacji znajdziesz w poście na blogu Przygotowanie aplikacji do obsługi SMS-ów na potrzeby KitKat.
Sieci bezprzewodowe i połączenia
host card emulation
Aplikacje na Androida mogą teraz emulować karty NFC ISO14443-4 (ISO-DEP), które do wymiany danych używają APDU (zgodnie z specyfikacją ISO7816-4). Dzięki temu urządzenie z Androidem w wersji 4.4 obsługujące komunikację NFC może emulować jednocześnie wiele kart NFC, a terminal płatniczy NFC lub inny czytnik NFC może zainicjować transakcję z odpowiednią kartą NFC na podstawie identyfikatora aplikacji (AID).
Jeśli chcesz emulować kartę NFC, która używa tych protokołów w aplikacji, utwórz komponent usługi na podstawie klasy HostApduService
. Jeśli jednak Twoja aplikacja używa bezpiecznego elementu do emulacji karty, musisz utworzyć usługę na podstawie klasy OffHostApduService
, która nie będzie bezpośrednio zaangażowana w transakcje, ale będzie potrzebna do rejestrowania identyfikatorów AID, które powinny być obsługiwane przez bezpieczny element.
Więcej informacji znajdziesz w przewodniku na temat emulacji karty NFC.
Tryb czytnika NFC
Nowy tryb czytnika NFC umożliwia ograniczenie wszystkich działań NFC do odczytu tylko tych typów tagów, które są potrzebne danej aktywności na pierwszym planie. Możesz włączyć tryb czytnika dla swojej aktywności za pomocą enableReaderMode()
, zapewniając implementację NfcAdapter.ReaderCallback
, która otrzyma wywołanie zwrotne po wykryciu nowych tagów.
Ta nowa funkcja w połączeniu z emulacją karty hosta umożliwia Androidowi działanie po obu stronach interfejsu płatności mobilnych: jedno urządzenie działa jako terminal płatniczy (urządzenie z aktywną aktywnością w trybie czytnika) i inne urządzenie jako klient płatności (urządzenie emulujące kartę NFC).
nadajniki podczerwieni.
Gdy aplikacja działa na urządzeniu z nadajnikiem podczerwieni (IR), możesz teraz przesyłać sygnały podczerwieni za pomocą interfejsów API ConsumerIrManager
. Aby uzyskać wystąpienie ConsumerIrManager
, wywołaj funkcję getSystemService()
, podając jako argument wartość CONSUMER_IR_SERVICE
. Następnie możesz zapytać o obsługiwane częstotliwości podczerwieni urządzenia za pomocą funkcji getCarrierFrequencies()
i przesyłać sygnały, podając żądaną częstotliwość i wzór sygnału za pomocą funkcji transmit()
.
Najpierw zawsze sprawdź, czy urządzenie ma nadajnik podczerwieni, wywołując funkcję hasIrEmitter()
. Jeśli jednak Twoja aplikacja jest zgodna tylko z urządzeniami z tym elementem, dodaj element <uses-feature>
do pliku manifestu dla "android.hardware.consumerir"
(FEATURE_CONSUMER_IR
).
Multimedia
Odtwarzanie adaptacyjne
Obsługa adaptacyjnego odtwarzania wideo jest teraz dostępna w interfejsach MediaCodec
, co umożliwia płynną zmianę rozdzielczości podczas odtwarzania na Surface
. Możesz przesyłać do dekodera ramki wejściowe o nowej rozdzielczości, a rozdzielczość buforów wyjściowych zmieniać bez znaczących przerw.
Możesz włączyć odtwarzanie adaptacyjne, dodając do MediaFormat
2 klucze, które określają maksymalną rozdzielczość wymaganą przez aplikację od kodeka: KEY_MAX_WIDTH
i KEY_MAX_HEIGHT
. Po dodaniu tych informacji do MediaFormat
możesz przekazać MediaFormat
do instancji MediaCodec
za pomocą configure()
.
Kodek będzie płynnie przechodzić między rozdzielczościami, które są równe tym wartościom lub mniejsze. Kodek może też obsługiwać rozdzielczości większe niż określone maksymalne (o ile mieszczą się one w granicach obsługiwanych profili), ale przejścia do większych rozdzielczości mogą nie być płynne.
Aby zmienić rozdzielczość podczas dekodowania wideo H.264, nadal umieszczaj klatki w kolejce za pomocą metody MediaCodec.queueInputBuffer(), ale pamiętaj, aby podać nowe wartości zestawu parametrów sekwencji (SPS) i zestawu parametrów obrazu (PPS) razem z klatką natychmiastowego odświeżenia dekodera (IDR) w jednym buforze.
Zanim spróbujesz skonfigurować kodek do odtwarzania adaptacyjnego, musisz sprawdzić, czy urządzenie obsługuje odtwarzanie adaptacyjne, wywołując isFeatureSupported(String)
z FEATURE_AdaptivePlayback
.
Uwaga: obsługa odtwarzania adaptacyjnego zależy od dostawcy. Niektóre kodeki mogą wymagać więcej pamięci na potrzeby wskazówek dotyczących większych rozdzielczości. Dlatego maksymalne rozdzielczości należy ustawić na podstawie dekodowanego materiału źródłowego.
Sygnatury czasowe dźwięku na żądanie
Aby ułatwić synchronizację dźwięku z obrazem, nowa klasa AudioTimestamp
zawiera szczegóły osi czasu dotyczące konkretnego „ramki” w strumieniu audio obsługiwanym przez AudioTrack
. Aby uzyskać najnowszą dostępną sygnaturę czasową, utwórz instancję obiektu AudioTimestamp
i przekaż ją do funkcji getTimestamp()
. Jeśli żądanie sygnatury czasowej się powiedzie, instancja AudioTrack
zostanie wypełniona pozycją w jednostkach klatek oraz szacowanym czasem, w którym dana klatka została wyświetlona lub ma zostać wyświetlona.
Możesz użyć wartości nanoTime
w funkcji AudioTimestamp
(która jest monotoniczna), aby znaleźć najbliższy powiązany kadr wideo w porównaniu z wartością framePosition
. Dzięki temu możesz pominąć, powielić lub interpolować klatki wideo, aby dopasować je do dźwięku. Możesz też określić różnicę czasowa między wartością nanoTime
a oczekiwanym czasem przyszłego klatki wideo (z uwzględnieniem częstotliwości próbkowania), aby przewidzieć, który element audio ma być odtworzony w tym samym momencie co klatka wideo.
Czytnik obrazów na powierzchni
Nowy interfejs API ImageReader
zapewnia bezpośredni dostęp do buforów obrazów w miarę ich renderowania w usługach Surface
. Obiekt ImageReader
możesz uzyskać za pomocą metody statycznej newInstance()
. Następnie wywołaj funkcję getSurface()
, aby utworzyć nowy element Surface
i przesłać dane obrazu do producenta, takiego jak MediaPlayer
lub MediaCodec
. Aby otrzymywać powiadomienia o dostępności nowych obrazów z urządzenia, zaimplementuj interfejs ImageReader.OnImageAvailableListener
i zarejestruj go w usługach setOnImageAvailableListener()
.
Gdy teraz przenosisz treści do Surface
, ImageReader.OnImageAvailableListener
otrzymuje wywołanie onImageAvailable()
za każdym razem, gdy pojawia się nowy obraz. Dzięki temu możesz uzyskać odpowiednią ImageReader
. Za pomocą funkcji ImageReader
możesz pobrać dane obrazu kadru jako obiekt Image
, wywołując funkcję acquireLatestImage()
lub acquireNextImage()
.
Obiekt Image
zapewnia bezpośredni dostęp do sygnatury czasowej, formatu, wymiarów i danych pikseli obrazu w elementach ByteBuffer
. Jednak aby klasa Image
mogła interpretować obrazy, muszą one mieć format zgodny z jednym z typów zdefiniowanych przez stałe w funkcjach ImageFormat
lub PixelFormat
.
Pomiar wartości szczytowej i RMS
Możesz teraz wysyłać zapytania o wartości szczytowe i RMS bieżącego strumienia audio z poziomu Visualizer
, tworząc nową instancję Visualizer.MeasurementPeakRms
i przekazując ją do getMeasurementPeakRms()
. Gdy wywołasz tę metodę, wartości szczytowe i RMS danego Visualizer.MeasurementPeakRms
są ustawiane na najnowsze zmierzone wartości.
Kompensacja głośności
LoudnessEnhancer
to nowa podklasa AudioEffect
, która umożliwia zwiększenie głośności MediaPlayer
lub AudioTrack
. Może to być szczególnie przydatne w połączeniu z nową metodą getMeasurementPeakRms()
, o której mowa powyżej, aby zwiększyć głośność ścieżek audio z mową podczas odtwarzania innych multimediów.
Piloty
W Androidzie 4.0 (poziom interfejsu API 14) wprowadzono interfejsy API RemoteControlClient
, które umożliwiają aplikacjom multimedialnym korzystanie z zdarzeń kontrolera multimediów z klientów zdalnych, np. sterowanie multimediami na ekranie blokady. Nowe interfejsy API RemoteController
umożliwiają tworzenie własnych pilotów zdalnych, a także innowacyjnych aplikacji i urządzeń peryferyjnych, które mogą kontrolować odtwarzanie dowolnej aplikacji multimedialnej zintegrowanej z RemoteControlClient
.
Aby zbudować kontroler zdalny, możesz zaimplementować interfejs użytkownika w dowolny sposób, ale aby przesyłać zdarzenia przycisku multimediów do aplikacji multimedialnej użytkownika, musisz utworzyć usługę, która rozszerza klasę NotificationListenerService
i zaimplementowuje interfejs RemoteController.OnClientUpdateListener
. Użycie NotificationListenerService
jako podstawy jest ważne, ponieważ zapewnia odpowiednie ograniczenia prywatności, które wymagają od użytkowników włączenia Twojej aplikacji jako odbiornika powiadomień w ustawieniach zabezpieczeń systemu.
Klasa NotificationListenerService
zawiera kilka abstrakcyjnych metod, które musisz zaimplementować, ale jeśli interesują Cię tylko zdarzenia kontrolera multimediów dotyczące odtwarzania multimediów, możesz pozostawić ich implementację pustą i zamiast tego skupić się na metodach RemoteController.OnClientUpdateListener
.
Oceny z urządzeń zdalnych
Android 4.4 rozszerza dotychczasowe możliwości klientów sterowania zdalnego (aplikacji, które otrzymują zdarzenia sterowania multimediami za pomocą RemoteControlClient
) o możliwość oceniania bieżącego utworu za pomocą pilota.
Nowa klasa Rating
zawiera informacje o ocenie użytkownika. Ocena jest określana przez styl oceny (RATING_HEART
, RATING_THUMB_UP_DOWN
, RATING_3_STARS
, RATING_4_STARS
, RATING_5_STARS
lub RATING_PERCENTAGE
) oraz wartość oceny odpowiednią dla tego stylu.
Aby umożliwić użytkownikom ocenianie utworów za pomocą pilota zdalnego sterowania:
- Wskaż, że chcesz udostępnić użytkownikowi interfejs oceny (jeśli dotyczy), dodając flagę
FLAG_KEY_MEDIA_RATING
w plikusetTransportControlFlags()
. - Zadzwoń na numer
editMetadata()
, aby pobraćRemoteControlClient.MetadataEditor
i przekazać goRATING_KEY_BY_USER
za pomocąaddEditableKey()
. - Następnie określ styl oceny, wywołując funkcję
putObject()
, przekazując jej jako klucza wartośćRATING_KEY_BY_USER
, a jako wartość jeden z wymienionych wyżej stylów oceny.
Aby otrzymywać wywołania zwrotne, gdy użytkownik zmieni ocenę za pomocą pilota zdalnego sterowania, zaimplementuj nowy interfejs RemoteControlClient.OnMetadataUpdateListener
i przekaż jego instancję do setMetadataUpdateListener()
. Gdy użytkownik zmieni ocenę, usługa RemoteControlClient.OnMetadataUpdateListener
otrzyma wywołanie metody onMetadataUpdate()
, przekazując jako klucz obiekt RATING_KEY_BY_USER
, a jako wartość obiekt Rating
.
Napisy
VideoView
obsługuje teraz ścieżki napisów WebVTT podczas odtwarzania filmów z transmisji na żywo przez HTTP (HLS), wyświetlając ścieżkę napisów zgodnie z preferencjami użytkownika zdefiniowanymi w ustawieniach systemu.
Możesz też przesłać ścieżki z napisami WebVTT do VideoView
, korzystając z metody addSubtitleSource()
. Ta metoda akceptuje obiekt InputStream
zawierający dane napisów oraz obiekt MediaFormat
określający format danych napisów, który możesz określić za pomocą createSubtitleFormat()
. Te napisy są też wyświetlane na filmie zgodnie z preferencjami użytkownika.
Jeśli nie używasz VideoView
do wyświetlania treści wideo, nakładka napisów powinna jak najlepiej odpowiadać ustawieniom napisów użytkownika. Nowy interfejs API CaptioningManager
umożliwia wysyłanie zapytań o ustawienia napisów użytkownika, w tym o style zdefiniowane przez CaptioningManager.CaptionStyle
, takie jak krój pisma i kolor. Jeśli użytkownik zmieni ustawienia po rozpoczęciu filmu, powinieneś sprawdzać zmiany w ustawieniach, rejestrując wystąpienie funkcji CaptioningManager.CaptioningChangeListener
, aby otrzymywać wywołania zwrotne w przypadku zmiany ustawień, a następnie zaktualizować napisy w razie potrzeby.
Animacja i grafika
Sceny i przejścia
Nowa platforma android.transition
udostępnia interfejsy API, które ułatwiają animacje między różnymi stanami interfejsu użytkownika. Kluczową funkcją jest możliwość definiowania różnych stanów interfejsu użytkownika, zwanych „scenami”, przez tworzenie osobnego układu dla każdego z nich. Jeśli chcesz animować przejście z jednej sceny do drugiej, wykonaj „przejście”, które oblicza niezbędną animację, aby zmienić układ bieżącej sceny na układ następnej.
Aby przejść między 2 scenami, musisz wykonać te czynności:
- Określ
ViewGroup
zawierający komponenty interfejsu użytkownika, które chcesz zmienić. - Określ układ, który będzie reprezentował końcowy wynik zmiany (następna scena).
- Określ typ przejścia, które ma animować zmianę układu.
- Wykonaj przejście.
Do wykonania kroków 1 i 2 możesz użyć obiektu Scene
. Plik Scene
zawiera metadane opisujące właściwości układu, które są niezbędne do wykonania przejścia, w tym widok nadrzędny sceny i układ sceny. Możesz utworzyć Scene
za pomocą konstruktora klasy lub metody statycznej getSceneForLayout()
.
Następnie do wykonania kroków 3 i 4 musisz użyć TransitionManager
. Jednym ze sposobów jest przekazanie wartości Scene
metodzie statycznej go()
. Szuka widoku nadrzędnego sceny w bieżącym układzie i przechodzi do widoków podrzędnych, aby dotrzeć do układu zdefiniowanego przez Scene
.
Nie musisz też tworzyć obiektu Scene
, ale możesz wywołać metodę beginDelayedTransition()
, podając obiekt ViewGroup
zawierający widoki, które chcesz zmienić. Następnie dodaj, usuń lub zmień konfigurację widoków docelowych. Gdy system wprowadzi zmiany, rozpocznie się animacja wszystkich widoków, których dotyczyły zmiany.
Aby uzyskać większą kontrolę, możesz zdefiniować zestawy przejść, które powinny występować między zdefiniowanymi wstępnie scenami, za pomocą pliku XML w katalogu projektu res/transition/
. Wewnątrz elementu <transitionManager>
określ co najmniej jeden tag <transition>
, który określa scenę (odwołuje się do pliku układu) i przejście stosowane podczas wchodzenia do tej sceny lub opuszczania jej. Następnie użyj instrukcji inflateTransitionManager()
, aby napełnić ten zestaw przejść. Użyj zwróconego obiektu TransitionManager
, aby wykonać każde przejście za pomocą obiektu transitionTo()
, przekazując obiekt Scene
, który jest reprezentowany przez jeden z tagów <transition>
. Możesz też definiować zestawy przejść programowo za pomocą interfejsów API TransitionManager
.
Podczas określania przejścia możesz użyć kilku wstępnie zdefiniowanych typów zdefiniowanych przez podklasy Transition
, takich jak Fade
i ChangeBounds
. Jeśli nie określisz typu przejścia, system domyślnie użyje AutoTransition
, które automatycznie powoduje płynne przejście między widokami, a także ich przemieszczanie i zmianę rozmiaru. Dodatkowo możesz tworzyć przejścia niestandardowe, rozszerzając dowolną z tych klas, aby wykonywać animacje w dowolny sposób. Niestandardowy przejście może śledzić dowolne zmiany właściwości i tworzyć na ich podstawie dowolne animacje. Możesz na przykład podać podklasę Transition
, która będzie nasłuchiwać zmian właściwości „rotation” widoku, a następnie animować wszelkie zmiany.
Więcej informacji znajdziesz w dokumentacji TransitionManager
.
Wstrzymywanie animacji
Interfejsy API Animator
umożliwiają teraz wstrzymywanie i wznawianie trwającej animacji za pomocą metod pause()
i resume()
.
Aby śledzić stan animacji, możesz zaimplementować interfejs Animator.AnimatorPauseListener
, który udostępnia wywołania zwrotne, gdy animacja zostanie wstrzymana i wznowiona: pause()
i resume()
. Następnie dodaj listenera do obiektu Animator
za pomocą funkcji addPauseListener()
.
Możesz też utworzyć podklasę abstrakcyjnej klasy AnimatorListenerAdapter
, która zawiera teraz puste implementacje wywołań zwrotnych wstrzymania i wznowienia zdefiniowanych przez Animator.AnimatorPauseListener
.
Grafiki rastrowe wielokrotnego użytku
Teraz możesz używać dowolnej bitmapy w BitmapFactory
do dekodowania dowolnej innej bitmapy, nawet jeśli nowa bitmapa ma inny rozmiar, o ile uzyskana liczba bajtów dekodowanej bitmapy (dostępna w getByteCount()
) jest mniejsza lub równa przydzielonej liczbie bajtów użytej ponownie bitmapy (dostępnej w getAllocationByteCount()
). Więcej informacji znajdziesz w artykule inBitmap
.
Nowe interfejsy API dla Bitmap
umożliwiają podobną konfigurację do ponownego użycia poza BitmapFactory
(np. do ręcznego generowania bitmap lub niestandardowej logiki dekodowania). Teraz możesz ustawiać wymiary bitmapy za pomocą metod setHeight()
i setWidth()
oraz określać nowe Bitmap.Config
za pomocą setConfig()
bez wpływu na podstawową alokację bitmapy. Metoda reconfigure()
umożliwia też wygodne łączenie tych zmian w jednym wywołaniu.
Nie należy jednak zmieniać konfiguracji bitmapy, której używa obecnie system widoku, ponieważ podrzędny bufor pikseli nie zostanie ponownie zmapowany w przewidywalny sposób.
Treści użytkowników
Ramy dostępu do pamięci
W poprzednich wersjach Androida, jeśli chcesz, aby Twoja aplikacja pobierała określony typ pliku z innej aplikacji, musi wywołać intencję z działaniem ACTION_GET_CONTENT
. Ta akcja jest nadal odpowiednim sposobem na żądanie pliku, który chcesz importować do aplikacji. Android 4.4 wprowadza jednak działanie ACTION_OPEN_DOCUMENT
, które pozwala użytkownikowi wybrać plik określonego typu i przyznasz aplikacji długoterminowy dostęp do odczytu tego pliku (ewentualnie z dostępem do zapisu) bez importowania go do aplikacji.
Jeśli tworzysz aplikację, która udostępnia usługi przechowywania plików (np. usługę zapisu w chmurze), możesz korzystać z tego zjednoczonego interfejsu użytkownika do wybierania plików, wdrażając dostawcę treści jako podklasę nowej klasy DocumentsProvider
. Podklasa DocumentsProvider
musi zawierać filtr intencji, który akceptuje działanie PROVIDER_INTERFACE
("android.content.action.DOCUMENTS_PROVIDER"
). Następnie musisz zaimplementować 4 abstrakcyjne metody w klasie DocumentsProvider
:
queryRoots()
- Zwracany musi być element
Cursor
opisujący wszystkie katalogi główne Twojego magazynu dokumentów, korzystając z kolumn zdefiniowanych wDocumentsContract.Root
. queryChildDocuments()
- Zapytanie musi zwracać
Cursor
, który opisuje wszystkie pliki w określonym katalogu, używając kolumn zdefiniowanych w pytaniuDocumentsContract.Document
. queryDocument()
- Musi zwracać
Cursor
, który opisuje podany plik, używając kolumn zdefiniowanych wDocumentsContract.Document
. openDocument()
- Musi zwrócić
ParcelFileDescriptor
reprezentujący określony plik. System wywołuje tę metodę, gdy użytkownik wybierze plik, a aplikacja klienta poprosi o dostęp do niego, wywołując metodęopenFileDescriptor()
.
Więcej informacji znajdziesz w ramach Storage Access Framework.
Dostęp do pamięci zewnętrznej
Teraz możesz odczytywać i zapisywać pliki związane z aplikacją na zewnętrznych nośnikach danych, np. gdy urządzenie obsługuje zarówno emulowaną pamięć masową, jak i kartę SD. Nowa metoda getExternalFilesDirs()
działa tak samo jak dotychczasowa metoda getExternalFilesDir()
, ale zwraca tablicę obiektów File
. Przed odczytem lub zapisem dowolnej ścieżki zwróconej przez tę metodę prześlij obiekt File
do nowej metody getStorageState()
, aby sprawdzić, czy pamięć jest obecnie dostępna.
Inne metody uzyskiwania dostępu do katalogu pamięci podręcznej i katalogu OBB konkretnej aplikacji mają teraz również odpowiadające im wersje, które zapewniają dostęp do urządzeń z pamięcią podręczną: getExternalCacheDirs()
i getObbDirs()
.
Pierwszy wpis w zwróconej tablicy File
jest uważany za główną pamięć zewnętrzną urządzenia, która jest taka sama jak File
zwracana przez istniejące metody, takie jak getExternalFilesDir()
.
Uwaga: od wersji Androida 4.4 aplikacja nie musi już uzyskiwać uprawnień WRITE_EXTERNAL_STORAGE
ani READ_EXTERNAL_STORAGE
, jeśli za pomocą powyższych metod chcesz uzyskać dostęp tylko do regionów zewnętrznego miejsca na dane, które są używane przez Twoją aplikację. Te uprawnienia są jednak wymagane, jeśli chcesz uzyskać dostęp do regionów udostępnionego miejsca na dane w pamięci zewnętrznej udostępnianej przez getExternalStoragePublicDirectory()
.
Adaptery synchronizacji
Nowa metoda requestSync()
w ContentResolver
upraszcza niektóre procedury definiowania żądania synchronizacji dla ContentProvider
, ponieważ żądania są umieszczane w nowym obiekcie SyncRequest
, który możesz utworzyć za pomocą metody SyncRequest.Builder
. Właściwości w SyncRequest
zapewniają tę samą funkcjonalność co istniejące wywołania synchronizacji ContentProvider
, ale umożliwiają też określenie, że synchronizacja powinna zostać przerwana, jeśli sieć jest płatna. Aby to zrobić, włącz setDisallowMetered()
.
Dane wejściowe użytkownika
Nowe typy czujników
Nowy czujnik TYPE_GEOMAGNETIC_ROTATION_VECTOR
dostarcza danych o wektorze obrotu na podstawie magnetometru, co jest przydatną alternatywą dla czujnika TYPE_ROTATION_VECTOR
, gdy żyroskop jest niedostępny lub gdy jest używany z zbiorczymi zdarzeniami czujnika do rejestrowania orientacji urządzenia, gdy telefon jest w stanie uśpienia. Ten czujnik wymaga mniej energii niż TYPE_ROTATION_VECTOR
, ale może być podatny na zakłócenia w danych zdarzeń i najskuteczniejszy jest wtedy, gdy użytkownik jest na zewnątrz.
Android obsługuje teraz też wbudowane czujniki kroków w sprzęcie:
TYPE_STEP_DETECTOR
- Ten czujnik powoduje wywołanie zdarzenia za każdym razem, gdy użytkownik wykona krok. Po każdym kroku użytkownika ten czujnik wysyła zdarzenie o wartości 1,0 i znacznik czasu wskazujący, kiedy krok miał miejsce.
TYPE_STEP_COUNTER
- Ten czujnik również powoduje wystąpienie zdarzenia po każdym wykrytym kroku, ale zamiast tego dostarcza łączną liczbę kroków od momentu zarejestrowania tego czujnika przez aplikację.
Pamiętaj, że te 2 czujniki kroków nie zawsze dają takie same wyniki. Zdarzenia TYPE_STEP_COUNTER
występują z większym opóźnieniem niż zdarzenia TYPE_STEP_DETECTOR
, ale wynika to z tego, że algorytm TYPE_STEP_COUNTER
wykonuje więcej operacji w celu wyeliminowania wyników fałszywie pozytywnych. W związku z tym TYPE_STEP_COUNTER
może działać wolniej, ale jego wyniki powinny być dokładniejsze.
Oba czujniki kroków są zależne od sprzętu (Nexus 5 jest pierwszym urządzeniem, które je obsługuje), dlatego należy sprawdzić dostępność za pomocą funkcji hasSystemFeature()
, używając stałych FEATURE_SENSOR_STEP_DETECTOR
i FEATURE_SENSOR_STEP_COUNTER
.
Zdarzenia czujnika w grupach
Aby lepiej zarządzać zużyciem energii przez urządzenie, interfejsy API SensorManager
umożliwiają teraz określenie częstotliwości, z jaką system ma dostarczać do aplikacji partie zdarzeń czujnika. Nie powoduje to zmniejszenia liczby rzeczywistych zdarzeń czujnika dostępnych dla aplikacji w danym okresie, ale zmniejsza częstotliwość wywoływania przez system interfejsu SensorEventListener
z aktualizacjami czujnika. Oznacza to, że zamiast przesyłać każde zdarzenie do aplikacji w momencie jego wystąpienia, system zapisuje wszystkie zdarzenia, które wystąpiły w danym przedziale czasu, a potem przesyła je do aplikacji od razu.
Aby umożliwić grupowanie, klasa SensorManager
dodaje 2 nowe wersje metody registerListener()
, które umożliwiają określenie „maksymalnego opóźnienia raportu”. Ten nowy parametr określa maksymalne opóźnienie, które SensorEventListener
będzie tolerować w przypadku przesyłania nowych zdarzeń czujnika. Jeśli np. określisz opóźnienie zbiorcze na 1 minutę, system będzie dostarczać ostatni zestaw zbiorczych zdarzeń z interwałem nie dłuższym niż 1 minuta, wykonując kolejne wywołania metody onSensorChanged()
– po jednym dla każdego zdarzenia, które zostało zgrupowane. Zdarzenia z czujników nigdy nie będą opóźnione dłużej niż o maksymalną wartość opóźnienia raportu, ale mogą docierać szybciej, jeśli inne aplikacje poproszą o krótsze opóźnienie dla tego samego czujnika.
Pamiętaj jednak, że czujnik będzie dostarczać aplikacji zdarzenia zbiorcze na podstawie opóźnienia raportu tylko wtedy, gdy procesor jest aktywny. Chociaż czujnik sprzętowy obsługujący grupowanie będzie nadal zbierać zdarzenia czujnika, gdy procesor będzie w stanie uśpienia, nie obudzi go, aby przekazać aplikacji zgrupowane zdarzenia. Gdy pamięć sensora się zapełni, zacznie on usuwać najstarsze zdarzenia, aby zapisać najnowsze. Aby uniknąć utraty zdarzeń, możesz aktywować urządzenie, zanim pamięć czujnika się zapełni, a następnie wywołać funkcję flush()
, aby zarejestrować najnowszą partię zdarzeń. Aby oszacować, kiedy pamięć będzie pełna i należy ją opróżnić, wywołaj funkcję getFifoMaxEventCount()
, aby uzyskać maksymalną liczbę zdarzeń czujnika, które można zapisać, a potem podziel tę liczbę przez częstotliwość, z jaką aplikacja potrzebuje każdego zdarzenia. Na podstawie tego obliczenia możesz ustawić alarmy wybudzania z AlarmManager
, które wywołują Service
(który implementuje SensorEventListener
), aby opróżnić pamięć podręczną czujnika.
Uwaga: nie wszystkie urządzenia obsługują grupowanie zdarzeń czujnika, ponieważ wymaga to obsługi przez czujnik sprzętowy. Jednak od wersji 4.4 Androida należy zawsze używać nowych metod registerListener()
, ponieważ jeśli urządzenie nie obsługuje zbiorczego przetwarzania, system ignoruje argument opóźnienia zbiorczego i przekazuje zdarzenia z czujnika w czasie rzeczywistym.
Tożsamości kontrolerów
Android identyfikuje teraz każdy podłączony kontroler za pomocą unikalnego bezwzględnego numeru, którego możesz użyć w zapytaniu getControllerNumber()
. Dzięki temu łatwiej będzie Ci powiązać kontroler z różnymi graczami w grze. Numer każdego kontrolera może się zmieniać, ponieważ użytkownik może odłączać, podłączać i ponownie konfigurować kontrolery. Dlatego powinieneś śledzić, który numer kontrolera odpowiada któremu urządzeniu wejściowemu, rejestrując instancję InputManager.InputDeviceListener
. Następnie wywołuj funkcję getControllerNumber()
dla każdego InputDevice
, gdy nastąpi zmiana.
Połączone urządzenia udostępniają teraz identyfikatory produktów i dostawców, które są dostępne w getProductId()
i getVendorId()
. Jeśli chcesz zmodyfikować mapowanie klawiszy na podstawie dostępnych klawiszy na urządzeniu, możesz wysłać zapytanie do urządzenia, aby sprawdzić, czy określone klawisze są dostępne za pomocą hasKeys(int...)
.
Interfejs
Tryb pełnoekranowy z efektem zanurzenia
Aby zapewnić aplikacji układ, który wypełnia cały ekran, nowa flaga SYSTEM_UI_FLAG_IMMERSIVE
dla setSystemUiVisibility()
(w połączeniu z SYSTEM_UI_FLAG_HIDE_NAVIGATION
) umożliwia nowy tryb pełnoekranowy immersive. Gdy włączony jest tryb pełnoekranowy, Twoja aktywność nadal rejestruje wszystkie zdarzenia dotykowe. Użytkownik może wyświetlić paski systemowe, przesuwając palcem w kierunku od krawędzi ekranu w obszarze, w którym paski te zwykle się pojawiają. Spowoduje to usunięcie flagi SYSTEM_UI_FLAG_HIDE_NAVIGATION
(i jeśli została zastosowana – flagi SYSTEM_UI_FLAG_FULLSCREEN
), dzięki czemu paski systemu pozostaną widoczne. Jeśli jednak chcesz, aby paski systemowe ponownie się ukryły po kilku chwilach, możesz użyć flagi SYSTEM_UI_FLAG_IMMERSIVE_STICKY
.
Przezroczyste paski systemu
Teraz możesz częściowo uczynić przezroczystymi paski systemu w ramach nowych motywów Theme.Holo.NoActionBar.TranslucentDecor
i Theme.Holo.Light.NoActionBar.TranslucentDecor
. Po włączeniu przezroczystych pasków systemowych układ wypełni obszar za nimi, dlatego musisz też włączyć fitsSystemWindows
dla części układu, która nie powinna być pokryta przez paski systemowe.
Jeśli tworzysz motyw niestandardowy, ustaw jeden z tych motywów jako motyw nadrzędny lub uwzględnij w nim właściwości stylu windowTranslucentNavigation
i windowTranslucentStatus
.
Ulepszona funkcja odbiornika powiadomień
W Androidzie 4.3 dodano interfejsy API NotificationListenerService
, które umożliwiają aplikacjom otrzymywanie informacji o nowych powiadomieniach w miarę ich wysyłania przez system. W Androidzie 4.4 odbiorcom powiadomień można pobrać dodatkowe metadane powiadomienia i szczegółowe informacje o działaniach powiadomienia:
Nowe pole Notification.extras
zawiera Bundle
, aby udostępniać kreatorowi powiadomień dodatkowe metadane, takie jak EXTRA_TITLE
i EXTRA_PICTURE
.
Nowa klasa Notification.Action
definiuje cechy działania dołączonego do powiadomienia, które możesz pobrać z nowego pola actions
.
Odzwierciedlanie elementów rysowalnych w przypadku układów od prawej do lewej
W poprzednich wersjach Androida, jeśli aplikacja zawiera obrazy, które powinny mieć odwróconą orientację poziomą na potrzeby układów z kierunkiem od prawej do lewej, musisz dołączyć odbicie lustrzane obrazu w katalogu zasobów drawables-ldrtl/
. System może teraz automatycznie odzwierciedlić obrazy, włączając atrybut autoMirrored
w zasobie do rysowania lub wywołując funkcję setAutoMirrored()
. Gdy ta opcja jest włączona, znak Drawable
jest automatycznie odwrócony, gdy kierunek układu jest od prawej do lewej.
Ułatwienia dostępu
Klasa View
umożliwia teraz deklarowanie „regionów na żywo” dla części interfejsu użytkownika, które dynamicznie aktualizują się za pomocą nowego tekstu. Aby to zrobić, dodaj nowy atrybut accessibilityLiveRegion
do układu XML lub wywołaj funkcję setAccessibilityLiveRegion()
. Na przykład ekran logowania z polem tekstowym, na którym wyświetla się powiadomienie „Nieprawidłowe hasło”, powinien być oznaczony jako region na żywo, aby czytnik ekranu odczytywał wiadomość po jej zmianie.
Aplikacje, które zapewniają usługę ułatwień dostępu, mogą teraz zwiększyć swoje możliwości dzięki nowym interfejsom API, które dostarczają informacji o zbiorach widoków, takich jak widok listy lub siatki, za pomocą funkcji AccessibilityNodeInfo.CollectionInfo
i AccessibilityNodeInfo.CollectionItemInfo
.
Uprawnienia aplikacji
Oto nowe uprawnienia, o które aplikacja musi prosić za pomocą tagu <uses-permission>
, aby używać niektórych nowych interfejsów API:
INSTALL_SHORTCUT
- Pozwala aplikacji zainstalować skrót w Menu z aplikacjami
UNINSTALL_SHORTCUT
- Zezwalanie aplikacji na odinstalowanie skrótu w Menu z aplikacjami
TRANSMIT_IR
- Zezwalanie aplikacji na używanie nadajnika podczerwieni w urządzeniu (jeśli jest dostępny)
Uwaga: od wersji 4.4 platforma nie wymaga już, aby aplikacja uzyskiwała uprawnienia WRITE_EXTERNAL_STORAGE
ani READ_EXTERNAL_STORAGE
, gdy chcesz uzyskać dostęp do regionów zewnętrznej pamięci masowej specyficznych dla aplikacji za pomocą takich metod jak getExternalFilesDir()
. Uprawnienia są jednak nadal wymagane, jeśli chcesz uzyskać dostęp do regionów udostępniania w miejscu zewnętrznym udostępnianym przez getExternalStoragePublicDirectory()
.
Funkcje urządzenia
Oto nowe funkcje urządzenia, które możesz zadeklarować za pomocą znacznika <uses-feature>
, aby określić wymagania dotyczące aplikacji i włączyć filtrowanie w Google Play lub sprawdzić w czasie działania:
FEATURE_CONSUMER_IR
- Urządzenie może komunikować się z urządzeniami IR dla konsumentów.
FEATURE_DEVICE_ADMIN
- Urządzenie obsługuje egzekwowanie zasad dotyczących urządzeń przez administratorów urządzeń.
FEATURE_NFC_HOST_CARD_EMULATION
- Urządzenie obsługuje emulację karty NFC na hoście.
FEATURE_SENSOR_STEP_COUNTER
- Urządzenie ma licznik kroków.
FEATURE_SENSOR_STEP_DETECTOR
- Urządzenie zawiera sprzętowy detektor kroków.
Szczegółowe informacje o wszystkich zmianach w interfejsie API w Androidzie 4.4 znajdziesz w raporcie Różnice w interfejsie API.