API-Level: 19
Android 4.4 (KITKAT
) ist ein neuer Release für die Android-Plattform, der neue Funktionen für Nutzer und App-Entwickler bietet. Dieses Dokument bietet eine Einführung in die wichtigsten neuen APIs.
Als App-Entwickler sollten Sie das System-Image und die SDK-Plattform für Android 4.4 so schnell wie möglich aus dem SDK-Manager herunterladen. Wenn Sie zum Testen Ihrer App kein Gerät mit Android 4.4 haben, testen Sie Ihre App mit dem System-Image von Android 4.4 im Android-Emulator. Erstellen Sie dann Ihre Apps auf der Plattform Android 4.4, um die neuesten APIs zu nutzen.
Ziel-API-Level aktualisieren
Wenn du deine App besser für Geräte mit Android 4.4 optimieren möchtest, solltest du targetSdkVersion
auf "19"
setzen, sie auf einem System-Image von Android 4.4 installieren, testen und dann ein Update mit dieser Änderung veröffentlichen.
Sie können APIs unter Android 4.4 verwenden und gleichzeitig ältere Versionen unterstützen. Fügen Sie Ihrem Code dazu Bedingungen hinzu, die das System-API-Level prüfen, bevor APIs ausgeführt werden, die von Ihrem minSdkVersion
nicht unterstützt werden.
Weitere Informationen zur Aufrechterhaltung der Abwärtskompatibilität findest du unter Unterstützung verschiedener Plattformversionen.
Weitere Informationen zur Funktionsweise von API-Levels finden Sie unter Was ist ein API-Level?
Wichtige Verhaltensänderungen
Wenn du bereits eine App für Android veröffentlicht hast, solltest du beachten, dass deine App von Änderungen in Android 4.4 betroffen sein kann.
Wenn Ihre App Daten aus dem externen Speicher liest...
Unter Android 4.4 kann deine App keine freigegebenen Dateien im externen Speicher lesen, es sei denn, sie hat die Berechtigung READ_EXTERNAL_STORAGE
. Das heißt, auf Dateien in dem von getExternalStoragePublicDirectory()
zurückgegebenen Verzeichnis kann nicht mehr ohne die Berechtigung zugegriffen werden. Wenn Sie jedoch nur auf die von getExternalFilesDir()
bereitgestellten App-spezifischen Verzeichnisse zugreifen möchten, benötigen Sie die Berechtigung READ_EXTERNAL_STORAGE
nicht.
Wenn Ihre App WebView verwendet...
Unter Android 4.4 verhält sich Ihre App möglicherweise anders, insbesondere wenn Sie targetSdkVersion
auf „19“ oder höher aktualisieren.
Der Code, der der WebView
-Klasse und den zugehörigen APIs zugrunde liegt, wurde aktualisiert. Er basiert nun auf einem modernen Snapshot des Chromium-Quellcodes. Dies umfasst eine Reihe von Leistungsverbesserungen, Unterstützung für neue HTML5-Funktionen und Unterstützung für die Fehlerbehebung Ihrer WebView
-Inhalte aus der Ferne. Wenn deine App WebView
verwendet, kann sich das in einigen Fällen auf das Verhalten auswirken. Änderungen des bekannten Verhaltens sind zwar dokumentiert und wirken sich hauptsächlich nur dann auf Ihre App aus, wenn Sie die targetSdkVersion
Ihrer App auf „19“ oder höher aktualisieren. Die neue WebView
wird im Quirks-Modus ausgeführt, um einige alte Funktionen in Apps bereitzustellen, die auf API-Level 18 oder niedriger ausgerichtet sind. Es ist aber möglich, dass Ihre App von unbekanntem Verhalten der vorherigen Version von WebView
abhängt.
Wenn deine bestehende App also WebView
verwendet, ist es wichtig, dass du sie so schnell wie möglich unter Android 4.4 testest. Unter Migration zu WebView in Android 4.4 findest du Informationen dazu, wie sich ein Update deiner targetSdkVersion
auf „19“ oder höher auf deine App auswirken könnte.
Wenn deine App AlarmManager verwendet...
Wenn du targetSdkVersion
deiner App auf „19“ oder höher einstellst, sind Alarme, die du mit set()
oder setRepeating()
erstellst, ungenau.
Um die Energieeffizienz zu verbessern, fasst Android jetzt Alarme von allen Apps zusammen, die zu ungefähr ähnlichen Zeiten auftreten, sodass das System das Gerät nur einmal anstatt mehrmals aufweckt, um jeden Alarm zu verarbeiten.
Wenn deinem Wecker keine genaue Uhrzeit zugeordnet ist, es aber wichtig ist, dass er innerhalb eines bestimmten Zeitraums aktiviert wird (z. B. zwischen 14:00 und 16:00 Uhr), kannst du die neue setWindow()
-Methode verwenden. Diese akzeptiert eine „früheste“ Zeit für den Alarm und ein „Zeitfenster“ nach der frühesten Zeit, in der das System den Alarm auslösen soll.
Wenn Ihr Wecker an eine genaue Uhrzeit angepinnt sein muss, z. B. für eine Kalenderterminerinnerung, können Sie die neue setExact()
-Methode verwenden.
Dieses ungenaue Batchverhalten gilt nur für aktualisierte Apps. Wenn Sie targetSdkVersion
auf „18“ oder niedriger eingestellt haben, funktionieren Ihre Wecker unter Android 4.4 wie in früheren Versionen.
Wenn Ihre App Daten mithilfe von ContentResolver synchronisiert...
Wenn Sie targetSdkVersion
Ihrer App auf „19“ oder höher festlegen und eine Synchronisierung mit addPeriodicSync()
erstellen, werden Ihre Synchronisierungsvorgänge innerhalb eines standardmäßigen flexiblen Intervalls von etwa 4% des von Ihnen angegebenen Zeitraums ausgeführt. Wenn die Abfragehäufigkeit beispielsweise 24 Stunden beträgt, kann die Synchronisierung täglich in einem Zeitfenster von etwa einer Stunde erfolgen, nicht jeden Tag genau zur gleichen Zeit.
Um Ihr eigenes Flex-Intervall für Synchronisierungsvorgänge anzugeben, sollten Sie die neue Methode requestSync()
verwenden. Weitere Informationen finden Sie unten im Abschnitt Synchronisierungsadapter.
Dieses Flex-Intervall gilt nur für aktualisierte Apps. Wenn Sie targetSdkVersion
auf „18“ oder niedriger gesetzt haben, verhalten sich Ihre vorhandenen Synchronisierungsanfragen unter Android 4.4 wie in früheren Versionen.
Drucksystem
Android umfasst jetzt ein umfassendes Framework, das es Nutzern ermöglicht, beliebige Dokumente mit einem über WLAN, Bluetooth oder anderen Diensten verbundenen Drucker zu drucken. Das System verarbeitet die Transaktion zwischen einer App, die ein Dokument drucken möchte, und den Diensten, die Druckaufträge an einen Drucker senden. Das android.print
-Framework stellt alle APIs bereit, die erforderlich sind, um ein Druckdokument anzugeben und es zum Drucken an das System zu senden. Welche APIs Sie für einen bestimmten Druckauftrag benötigen, hängt von Ihrem Inhalt ab.
Allgemeine Inhalte drucken
Wenn Sie Inhalte aus Ihrer UI als Dokument drucken möchten, müssen Sie zuerst eine abgeleitete Klasse von PrintDocumentAdapter
erstellen. Innerhalb dieser Klasse musst du einige Callback-Methoden implementieren, z. B. onLayout()
, um dein Layout anhand der bereitgestellten Druckeigenschaften festzulegen, und onWrite()
, um deine druckbaren Inhalte in eine ParcelFileDescriptor
zu serialisieren.
Um Ihre Inhalte an ParcelFileDescriptor
schreiben zu können, müssen Sie sie als PDF-Datei übergeben. Eine bequeme Möglichkeit dafür bieten die neuen PdfDocument
APIs. Sie stellen eine Canvas
aus getCanvas()
bereit, auf der Sie Ihre druckbaren Inhalte zeichnen können. Schreiben Sie dann mit der Methode writeTo()
die PdfDocument
in ParcelFileDescriptor
.
Nachdem Sie die Implementierung für PrintDocumentAdapter
definiert haben, können Sie Druckaufträge auf Anfrage des Nutzers mit der PrintManager
-Methode print()
ausführen. Dabei wird PrintDocumentAdapter
als Argument verwendet.
Bilder drucken
Wenn Sie nur ein Foto oder eine andere Bitmap drucken möchten, erledigen die Hilfs-APIs in der Supportbibliothek die Arbeit für Sie. Erstellen Sie einfach eine neue Instanz von PrintHelper
, legen Sie den Skalierungsmodus auf setScaleMode()
fest und übergeben Sie dann Bitmap
an printBitmap()
. Das wars. Die Bibliothek verarbeitet die gesamte verbleibende Interaktion mit dem System, um die Bitmap an den Drucker zu senden.
Druckdienste erstellen
Als OEM von Druckern können Sie das android.printservice
-Framework verwenden, um Interoperabilität mit Ihren Druckern über Android-Geräte zu ermöglichen. Sie können Druckdienste als APKs erstellen und verteilen, die Nutzer auf ihren Geräten installieren können . Eine Druckdienst-App wird in erster Linie als monitorloser Dienst ausgeführt. Dazu erstellt sie eine Unterklasse der PrintService
-Klasse, die Druckaufträge vom System empfängt und die Aufträge über die entsprechenden Protokolle an ihre Drucker sendet.
Weitere Informationen zum Drucken von App-Inhalten finden Sie unter Inhalte drucken.
SMS-Anbieter
Der Contentanbieter Telephony
(„SMS-Anbieter“) erlaubt Apps, SMS und MMS auf dem Gerät zu lesen und zu schreiben. Er enthält Tabellen für empfangene, Entwurfs, gesendete, ausstehende und ausstehende SMS- und MMS-Nachrichten.
Ab Android 4.4 können Nutzer in den Systemeinstellungen eine „Standard-SMS-App“ auswählen. Nach der Auswahl kann nur die Standard-SMS-App Daten an den SMS-Anbieter senden. Wenn der Nutzer eine SMS erhält, empfängt nur die Standard-SMS-App die SMS_DELIVER_ACTION
-Nachricht bzw. die WAP_PUSH_DELIVER_ACTION
-Nachricht, wenn der Nutzer eine MMS erhält. Die Standard-SMS-App ist für das Schreiben von Details an den SMS-Anbieter verantwortlich, wenn dieser eine neue Nachricht empfängt oder sendet.
Andere Apps, die nicht als Standard-SMS-App ausgewählt sind, können nur den SMS-Anbieter lesen und sich auch benachrichtigen lassen, wenn eine neue SMS eingeht, indem die SMS_RECEIVED_ACTION
-Nachricht angehört wird. Diese Übertragung kann nicht abgebrochen werden, die an mehrere Apps gesendet werden kann. Dieser Broadcast ist für Apps vorgesehen, die zwar nicht als Standard-SMS-App ausgewählt sind, aber besondere eingehende Nachrichten lesen müssen, z. B. zur Bestätigung der Telefonnummer.
Weitere Informationen finden Sie im Blogpost Getting Your SMS Apps Ready for KitKat.
WLAN und Konnektivität
Host-Kartenemulation
Android-Apps können jetzt ISO14443-4 (ISO-DEP) NFC-Karten emulieren, die APDUs für den Datenaustausch verwenden (gemäß ISO7816-4). Dadurch kann ein NFC-fähiges Gerät mit Android 4.4 mehrere NFC-Karten gleichzeitig emulieren und ein NFC-Zahlungsterminal oder ein anderes NFC-Lesegerät kann eine Transaktion mit der entsprechenden NFC-Karte basierend auf der App-ID (AID) initiieren.
Wenn Sie eine NFC-Karte emulieren möchten, die diese Protokolle in Ihrer App verwendet, erstellen Sie eine Dienstkomponente auf Basis der HostApduService
-Klasse. Wenn deine App stattdessen ein Secure Element für die Kartenemulation verwendet, musst du einen Dienst auf Basis der OffHostApduService
-Klasse erstellen, der nicht direkt an den Transaktionen beteiligt ist, aber zum Registrieren der AIDs erforderlich ist, die vom Secure Element verarbeitet werden sollen.
Weitere Informationen finden Sie in der Anleitung zur NFC-Kartenemulation.
NFC-Lesemodus
Ein neuer NFC-Lesemodus ermöglicht es einer Aktivität, alle NFC-Aktivitäten auf das Lesen der Tag-Typen zu beschränken, an denen die Aktivität im Vordergrund interessiert ist. Du kannst den Lesemodus für deine Aktivität mit enableReaderMode()
aktivieren und eine Implementierung von NfcAdapter.ReaderCallback
bereitstellen, die einen Callback empfängt, wenn neue Tags erkannt werden.
Diese neue Funktion ermöglicht in Verbindung mit der Hostkartenemulation, dass Android an beiden Enden einer mobilen Zahlungsschnittstelle arbeitet: Ein Gerät fungiert als Zahlungsterminal (ein Gerät, das eine Lesemodus-Aktivität ausführt), und ein anderes Gerät als Zahlungsclient (ein Gerät, das eine NFC-Karte emuliert).
Infrarotsender
Wenn das Gerät mit einem Infrarotsender (IR) betrieben wird, können Sie jetzt IR-Signale über die ConsumerIrManager
APIs übertragen. Um eine Instanz von ConsumerIrManager
abzurufen, rufen Sie getSystemService()
mit CONSUMER_IR_SERVICE
als Argument auf. Anschließend kannst du die vom Gerät unterstützten IR-Frequenzen mit getCarrierFrequencies()
abfragen und Signale übertragen, indem du die gewünschte Frequenz und das Signalmuster mit transmit()
übergibst.
Du solltest zuerst immer zuerst prüfen, ob ein Gerät einen IR-Sender enthält, indem du hasIrEmitter()
aufrufst. Wenn deine App jedoch nur mit Geräten kompatibel ist, die einen IR-Sender haben, solltest du ein <uses-feature>
-Element in dein Manifest für "android.hardware.consumerir"
(FEATURE_CONSUMER_IR
) aufnehmen.
Multimedia
Adaptive Wiedergabe
Die MediaCodec
-APIs unterstützen jetzt die adaptive Videowiedergabe. Dies ermöglicht eine nahtlose Änderung der Auflösung während der Wiedergabe auf einem Surface
. Du kannst die Decoder-Eingabeframes mit einer neuen Auflösung einspeisen und die Auflösung der Ausgabezwischenspeicher ändert sich ohne größere Lücke.
Du kannst die adaptive Wiedergabe aktivieren, indem du zwei Schlüssel zu MediaFormat
hinzufügst, die die maximale Auflösung angeben, die deine App aus den Codec KEY_MAX_WIDTH
und KEY_MAX_HEIGHT
benötigt. Wenn Sie diese Ihrem MediaFormat
hinzufügen, übergeben Sie das MediaFormat
mit configure()
an Ihre MediaCodec
-Instanz.
Der Codec wechselt nahtlos zwischen Auflösungen, die gleich oder kleiner als diese Werte sind. Der Codec unterstützt möglicherweise auch Auflösungen, die größer als die angegebenen Höchstwerte sind (solange diese innerhalb der Grenzen der unterstützten Profile liegt). Übergänge zu größeren Auflösungen sind jedoch eventuell nicht nahtlos.
Um die Auflösung beim Decodieren des H.264-Videos zu ändern, stellen Sie die Frames weiterhin mit MediaCodec.queueInputBuffer() in die Warteschlange, aber stellen Sie sicher, dass Sie die neuen Werte für Sequence Parameter Set (SPS) und Picture Parameter Set (PPS) zusammen mit dem Frame für Instantaneous Decoder Refresh (IDR) in einem einzigen Zwischenspeicher bereitstellen.
Bevor du jedoch versuchst, deinen Codec für die adaptive Wiedergabe zu konfigurieren, musst du prüfen, ob das Gerät die adaptive Wiedergabe unterstützt. Rufe dazu isFeatureSupported(String)
mit FEATURE_AdaptivePlayback
auf.
Hinweis:Die Unterstützung der adaptiven Wiedergabe ist anbieterspezifisch. Einige Codecs benötigen möglicherweise mehr Arbeitsspeicher, um Hinweise mit höherer Auflösung zu erhalten. Daher sollten Sie die maximalen Auflösungen auf Grundlage des Quellmaterials festlegen, das Sie decodieren.
On-Demand-Audiozeitstempel
Die neue AudioTimestamp
-Klasse bietet Zeitachsendetails zu einem bestimmten „Frame“ in einem Audiostream, der von AudioTrack
verarbeitet wird, um die Synchronisierung von Audio und Video zu vereinfachen. Instanziieren Sie ein AudioTimestamp
-Objekt und übergeben Sie es an getTimestamp()
, um den neuesten verfügbaren Zeitstempel zu erhalten. Wenn die Anfrage für den Zeitstempel erfolgreich ist, werden für die AudioTrack
-Instanz eine Position in Frameeinheiten sowie die geschätzte Zeit angegeben, zu der dieser Frame entweder präsentiert oder per Commit übergeben wurde.
Sie können den Wert von nanoTime
im AudioTimestamp
(monoton) verwenden, um den am nächsten gelegenen Videoframe im Vergleich zu framePosition
zu finden. So können Sie Videoframes entfernen, duplizieren oder interpolieren, um den Ton anzupassen. Alternativ können Sie die Deltazeit zwischen dem Wert von nanoTime
und der erwarteten Zeit eines zukünftigen Videoframes (unter Berücksichtigung der Abtastrate) bestimmen, um vorherzusagen, welcher Audioframe genau zum selben Zeitpunkt wie ein Videoframe erwartet wird.
Oberflächen-Bildlesegerät
Die neue ImageReader
API bietet Ihnen direkten Zugriff auf Bildzwischenspeicher, wenn diese in Surface
gerendert werden. Sie können ein ImageReader
mit der statischen Methode newInstance()
abrufen. Rufen Sie dann getSurface()
auf, um eine neue Surface
zu erstellen und Ihre Bilddaten an einen Ersteller wie MediaPlayer
oder MediaCodec
zu senden. Implementieren Sie die ImageReader.OnImageAvailableListener
-Schnittstelle und registrieren Sie sie bei setOnImageAvailableListener()
, um benachrichtigt zu werden, wenn neue Bilder von der Oberfläche verfügbar sind.
Wenn Sie jetzt Inhalte auf Surface
zeichnen, erhält ImageReader.OnImageAvailableListener
einen Aufruf von onImageAvailable()
, sobald jeder neue Bildframe verfügbar ist, und stellt Ihnen die entsprechende ImageReader
zur Verfügung. Sie können das ImageReader
verwenden, um die Bilddaten des Frames als Image
-Objekt zu erfassen, indem Sie acquireLatestImage()
oder acquireNextImage()
aufrufen.
Das Image
-Objekt bietet direkten Zugriff auf den Zeitstempel, das Format, die Abmessungen und die Pixeldaten des Bildes in einer ByteBuffer
. Damit die Image
-Klasse Ihre Bilder jedoch interpretieren kann, müssen sie gemäß einem der durch Konstanten in ImageFormat
oder PixelFormat
definierten Typen formatiert werden.
Spitzen- und RMS-Messung
Sie können jetzt den Spitzenwert und den RMS-Wert des aktuellen Audiostreams aus Visualizer
abfragen, indem Sie eine neue Instanz von Visualizer.MeasurementPeakRms
erstellen und an getMeasurementPeakRms()
übergeben. Wenn Sie diese Methode aufrufen, werden die Spitzen- und RMS-Werte der gegebenen Visualizer.MeasurementPeakRms
auf die letzten gemessenen Werte eingestellt.
Lautstärkeverstärker
LoudnessEnhancer
ist eine neue abgeleitete Klasse von AudioEffect
, mit der Sie die Lautstärke von MediaPlayer
oder AudioTrack
erhöhen können. Das kann besonders in Verbindung mit der oben erwähnten neuen getMeasurementPeakRms()
-Methode nützlich sein, um die Lautstärke der gesprochenen Audiotracks zu erhöhen, während andere Medien wiedergegeben werden.
Fernbedienungen
Mit Android 4.0 (API-Level 14) wurden die RemoteControlClient
APIs eingeführt, mit denen Medien-Apps Medien-Controller-Ereignisse von Remote-Clients wie Mediensteuerelemente auf dem Sperrbildschirm abrufen können. Mit den neuen RemoteController
APIs kannst du jetzt deine eigene Fernbedienung erstellen und so innovative neue Apps und Peripheriegeräte entwickeln, mit denen du die Wiedergabe von Medien-Apps steuern kannst, die in RemoteControlClient
integriert sind.
Wenn Sie einen Remote-Controller erstellen möchten, können Sie Ihre Benutzeroberfläche beliebig implementieren. Um die Medienschaltflächenereignisse an die Medien-App des Nutzers zu senden, müssen Sie jedoch einen Dienst erstellen, der die NotificationListenerService
-Klasse erweitert und die RemoteController.OnClientUpdateListener
-Schnittstelle implementiert. Die Verwendung von NotificationListenerService
als Grundlage ist wichtig, da sie geeignete Datenschutzeinschränkungen bietet, sodass Nutzer deine App in den Sicherheitseinstellungen des Systems als Benachrichtigungs-Listener aktivieren müssen.
Die Klasse NotificationListenerService
enthält einige abstrakte Methoden, die Sie implementieren müssen. Wenn es Ihnen jedoch nur um die Mediencontroller-Ereignisse zur Verarbeitung der Medienwiedergabe geht, können Sie die Implementierung leer lassen und sich stattdessen auf die RemoteController.OnClientUpdateListener
-Methoden konzentrieren.
Bewertungen von Fernbedienungen
Android 4.4 baut auf den vorhandenen Funktionen für Fernbedienungsclients auf (Apps, die Mediensteuerungsereignisse über die RemoteControlClient
empfangen), indem Nutzern die Möglichkeit hinzugefügt wird, den aktuellen Titel über die Fernbedienung zu bewerten.
Die neue Rating
-Klasse enthält Informationen zu einer Nutzerbewertung. Eine Bewertung wird durch ihren Bewertungsstil (entweder RATING_HEART
, RATING_THUMB_UP_DOWN
, RATING_3_STARS
, RATING_4_STARS
, RATING_5_STARS
oder RATING_PERCENTAGE
) und den Bewertungswert definiert, der für diesen Stil geeignet ist.
So ermöglichen Sie Nutzern, Titel über einen Remote-Controller zu bewerten:
- Signalisieren Sie, dass Sie die Bewertungs-UI für Nutzer sichtbar machen möchten (falls zutreffend), indem Sie das Flag
FLAG_KEY_MEDIA_RATING
insetTransportControlFlags()
hinzufügen. - Rufen Sie
editMetadata()
auf, um einRemoteControlClient.MetadataEditor
abzurufen, und übergeben Sie esRATING_KEY_BY_USER
mitaddEditableKey()
. - Legen Sie dann den Bewertungsstil fest, indem Sie
putObject()
aufrufen undRATING_KEY_BY_USER
als Schlüssel und einen der oben genannten Bewertungsstile als Wert übergeben.
Um einen Callback zu erhalten, wenn der Nutzer die Bewertung über die Remote-Steuerung ändert, implementiere die neue RemoteControlClient.OnMetadataUpdateListener
-Schnittstelle und übergib eine Instanz an setMetadataUpdateListener()
. Wenn der Nutzer die Bewertung ändert, erhält dein RemoteControlClient.OnMetadataUpdateListener
einen Aufruf von onMetadataUpdate()
, wobei RATING_KEY_BY_USER
als Schlüssel und ein Rating
-Objekt als Wert übergeben werden.
Untertitel
VideoView
unterstützt jetzt WebVTT-Untertitel beim Abspielen von HLS-Videos (HTTP-Livestream). Dabei wird der Untertiteltrack gemäß den vom Nutzer in den Systemeinstellungen festgelegten Untertiteleinstellungen angezeigt.
Du kannst VideoView
auch mit deinen WebVTT-Untertiteln über die addSubtitleSource()
-Methode bereitstellen. Diese Methode akzeptiert ein InputStream
, das die Untertiteldaten enthält, und ein MediaFormat
-Objekt, das das Format für die Untertiteldaten angibt, das du mit createSubtitleFormat()
angeben kannst. Diese Untertitel werden je nach Nutzereinstellungen auch über dem Video angezeigt.
Wenn du VideoView
nicht zum Anzeigen deiner Videoinhalte verwendest, solltest du darauf achten, dass dein Untertitel-Overlay den Untertitelpräferenzen des Nutzers so genau wie möglich entspricht. Mit der neuen CaptioningManager
API kannst du die Untertitel-Einstellungen des Nutzers abfragen. Dazu gehören auch durch CaptioningManager.CaptionStyle
definierte Stile wie Schriftart und Farbe. Für den Fall, dass der Nutzer einige Einstellungen anpasst, nachdem Ihr Video bereits gestartet wurde, sollten Sie auf Änderungen warten. Dazu registrieren Sie eine Instanz von CaptioningManager.CaptioningChangeListener
, um einen Callback zu erhalten, wenn sich die Einstellungen ändern. Aktualisieren Sie dann Ihre Untertitel nach Bedarf.
Animation und Grafik
Szenen und Übergänge
Das neue android.transition
-Framework stellt APIs bereit, die Animationen zwischen verschiedenen Status der Benutzeroberfläche ermöglichen. Ein wichtiges Merkmal ist die Möglichkeit, verschiedene Stadien Ihrer Benutzeroberfläche, sogenannte „Szenen“, zu definieren, indem Sie für jeden Status ein separates Layout erstellen. Wenn Sie von einer Szene zur nächsten animieren möchten, führen Sie einen „Übergang“ aus. Dieser berechnet die erforderliche Animation, um das Layout von der aktuellen Szene zur nächsten zu ändern.
Für den Wechsel zwischen zwei Szenen müssen im Allgemeinen folgende Schritte ausgeführt werden:
- Geben Sie die
ViewGroup
mit den UI-Komponenten an, die Sie ändern möchten. - Gib das Layout an, das das Endergebnis der Änderung darstellt (nächste Szene).
- Geben Sie die Art des Übergangs an, mit dem die Layoutänderung animiert werden soll.
- Führen Sie die Umstellung aus.
Sie können die Schritte 1 und 2 mit einem Scene
-Objekt ausführen. Ein Scene
enthält Metadaten, die die Eigenschaften eines Layouts beschreiben, die zum Ausführen eines Übergangs erforderlich sind. Dazu gehören die übergeordnete Ansicht der Szene und das Layout der Szene. Sie können einen Scene
mit einem Klassenkonstruktor oder der statischen Methode getSceneForLayout()
erstellen.
Anschließend müssen Sie die TransitionManager
verwenden, um die Schritte 3 und 4 auszuführen. Eine Möglichkeit besteht darin, Scene
an die statische Methode go()
zu übergeben. Dadurch wird die übergeordnete Ansicht der Szene im aktuellen Layout gesucht und ein Übergang für die untergeordneten Ansichten ausgeführt, um das durch Scene
definierte Layout zu erreichen.
Alternativ müssen Sie überhaupt kein Scene
-Objekt erstellen, sondern können stattdessen beginDelayedTransition()
aufrufen und dabei eine ViewGroup
angeben, die die zu ändernden Ansichten enthält. Fügen Sie dann die Zielansichten hinzu, entfernen oder konfigurieren Sie sie neu. Nachdem das System die Änderungen nach Bedarf definiert hat, beginnt ein Übergang, alle betroffenen Ansichten zu animieren.
Für zusätzliche Kontrolle können Sie Gruppen von Übergängen definieren, die zwischen vordefinierten Szenen stattfinden sollen. Verwenden Sie dazu eine XML-Datei im Projektverzeichnis res/transition/
. Geben Sie in einem <transitionManager>
-Element ein oder mehrere <transition>
-Tags an, die jeweils eine Szene (ein Verweis auf eine Layoutdatei) und den Übergang angeben, der beim Betreten und/oder Verlassen dieser Szene angewendet werden soll. Blasen Sie dann diese Gruppe von Übergängen mit inflateTransitionManager()
auf. Verwenden Sie das zurückgegebene TransitionManager
, um jeden Übergang mit transitionTo()
auszuführen. Übergeben Sie dabei ein Scene
, das durch eines der <transition>
-Tags dargestellt wird. Mit den TransitionManager
APIs können Sie Übergänge auch programmatisch definieren.
Wenn Sie einen Übergang angeben, können Sie mehrere vordefinierte Typen verwenden, die durch abgeleitete Klassen von Transition
definiert sind, z. B. Fade
und ChangeBounds
. Wenn Sie keinen Übergangstyp angeben, verwendet das System standardmäßig AutoTransition
. Damit werden Ansichten nach Bedarf automatisch ausgeblendet, verschoben und ihre Größe angepasst. Außerdem können Sie benutzerdefinierte Übergänge erstellen, indem Sie jede dieser Klassen so erweitern, dass die Animationen nach Belieben ausgeführt werden. Mit einem benutzerdefinierten Übergang können Sie beliebige Eigenschaftenänderungen verfolgen und auf der Grundlage dieser Änderungen Animationen erstellen, die Sie erstellen möchten. Sie können beispielsweise eine Unterklasse von Transition
bereitstellen, die auf Änderungen an der Rotationseigenschaft einer Ansicht wartet und dann alle Änderungen animiert.
Weitere Informationen finden Sie in der Dokumentation zu TransitionManager
.
Animator pausiert
Mit den Animator
APIs können Sie jetzt laufende Animationen mit den Methoden pause()
und resume()
anhalten und fortsetzen.
Um den Status einer Animation zu verfolgen, können Sie die Animator.AnimatorPauseListener
-Schnittstelle implementieren, die Callbacks bereitstellt, wenn eine Animation pausiert und fortgesetzt wird: pause()
und resume()
. Fügen Sie dann den Listener einem Animator
-Objekt mit addPauseListener()
hinzu.
Alternativ können Sie eine abgeleitete Klasse der abstrakten Klasse AnimatorListenerAdapter
erstellen, die jetzt leere Implementierungen für die Pausen- und Fortsetzungs-Callbacks enthält, die durch Animator.AnimatorPauseListener
definiert sind.
Wiederverwendbare Bitmaps
Sie können jetzt eine beliebige änderbare Bitmap in BitmapFactory
wiederverwenden, um andere Bitmap zu decodieren, selbst wenn die neue Bitmap eine andere Größe hat – vorausgesetzt, die resultierende Bytezahl der decodierten Bitmap (verfügbar bei getByteCount()
) ist kleiner oder gleich der zugewiesenen Bytezahl der wiederverwendeten Bitmap (verfügbar ab getAllocationByteCount()
). Weitere Informationen findest du unter inBitmap
.
Neue APIs für Bitmap
ermöglichen eine ähnliche Neukonfiguration zur Wiederverwendung außerhalb von BitmapFactory
(für die manuelle Bitmap-Generierung oder benutzerdefinierte Decodierungslogik). Du kannst jetzt die Abmessungen einer Bitmap mit den Methoden setHeight()
und setWidth()
festlegen und mit setConfig()
eine neue Bitmap.Config
angeben, ohne dass sich dies auf die zugrunde liegende Bitmapzuordnung auswirkt. Die Methode reconfigure()
bietet auch eine bequeme Möglichkeit, diese Änderungen mit einem Aufruf zu kombinieren.
Sie sollten jedoch eine Bitmap, die derzeit vom Ansichtssystem verwendet wird, nicht neu konfigurieren, da der zugrunde liegende Pixelzwischenspeicher nicht vorhersehbar neu zugeordnet wird.
Nutzerinhalte
Storage Access Framework
Wenn Sie in früheren Android-Versionen möchten, dass Ihre App einen bestimmten Dateityp aus einer anderen App abruft, muss sie einen Intent mit der Aktion ACTION_GET_CONTENT
aufrufen. Diese Aktion ist immer noch die geeignete Methode, um eine Datei anzufordern, die Sie in Ihre App importieren möchten. In Android 4.4 wird jedoch die Aktion ACTION_OPEN_DOCUMENT
eingeführt, mit der Nutzer eine Datei eines bestimmten Typs auswählen und Ihrer App langfristig Lesezugriff auf diese Datei (möglicherweise mit Schreibzugriff) gewähren können, ohne die Datei in Ihre App zu importieren.
Wenn Sie eine App entwickeln, die Speicherdienste für Dateien bereitstellt (z. B. einen Cloud-Speicherdienst), können Sie diese einheitliche Benutzeroberfläche zum Auswählen von Dateien nutzen. Implementieren Sie dazu einen Contentanbieter als Unterklasse der neuen DocumentsProvider
-Klasse. Ihre Unterklasse von DocumentsProvider
muss einen Intent-Filter enthalten, der die PROVIDER_INTERFACE
-Aktion ("android.content.action.DOCUMENTS_PROVIDER"
) akzeptiert. Anschließend müssen Sie die vier abstrakten Methoden in der DocumentsProvider
implementieren:
queryRoots()
- Es muss ein
Cursor
zurückgegeben werden, das alle Stammverzeichnisse Ihres Dokumentenspeichers anhand der inDocumentsContract.Root
definierten Spalten beschreibt. queryChildDocuments()
- Es muss ein
Cursor
zurückgegeben werden, das alle Dateien im angegebenen Verzeichnis anhand der inDocumentsContract.Document
definierten Spalten beschreibt. queryDocument()
- Es muss ein
Cursor
zurückgegeben werden, das die angegebene Datei anhand der inDocumentsContract.Document
definierten Spalten beschreibt. openDocument()
- Es muss ein
ParcelFileDescriptor
zurückgegeben werden, das die angegebene Datei darstellt. Das System ruft diese Methode auf, sobald der Nutzer eine Datei ausgewählt hat und die Client-App durch Aufrufen vonopenFileDescriptor()
Zugriff darauf anfordert.
Weitere Informationen finden Sie im Leitfaden Storage Access Framework.
Zugriff auf externen Speicher
Sie können jetzt app-spezifische Dateien auf sekundären externen Speichermedien lesen und schreiben, z. B. wenn ein Gerät sowohl emulierten Speicher als auch eine SD-Karte bietet. Die neue Methode getExternalFilesDirs()
funktioniert genauso wie die vorhandene Methode getExternalFilesDir()
, mit der Ausnahme, dass sie ein Array von File
-Objekten zurückgibt. Bevor Sie in einen der von dieser Methode zurückgegebenen Pfade lesen oder schreiben, müssen Sie das File
-Objekt an die neue getStorageState()
-Methode übergeben, um zu prüfen, ob der Speicherplatz derzeit verfügbar ist.
Andere Methoden für den Zugriff auf Ihr app-spezifisches Cache-Verzeichnis und das OBB-Verzeichnis haben jetzt auch entsprechende Versionen, die Zugriff auf sekundäre Speichergeräte ermöglichen: getExternalCacheDirs()
bzw. getObbDirs()
.
Der erste Eintrag im zurückgegebenen File
-Array wird als primärer externer Speicher des Geräts betrachtet. Dieser entspricht dem File
, der von vorhandenen Methoden wie getExternalFilesDir()
zurückgegeben wird.
Hinweis:Ab Android 4.4 ist es für die Plattform nicht mehr erforderlich, dass deine App WRITE_EXTERNAL_STORAGE
oder READ_EXTERNAL_STORAGE
erwirbt, wenn du mit den oben genannten Methoden nur auf deine app-spezifischen Regionen des externen Speichers zugreifen musst. Die Berechtigungen sind jedoch erforderlich, wenn Sie auf die gemeinsam nutzbaren Regionen des externen Speichers von getExternalStoragePublicDirectory()
zugreifen möchten.
Adapter synchronisieren
Die neue requestSync()
-Methode in ContentResolver
vereinfacht einige der Schritte zum Definieren einer Synchronisierungsanfrage für deine ContentProvider
, indem Anfragen im neuen SyncRequest
-Objekt gekapselt werden, das du mit SyncRequest.Builder
erstellen kannst. Die Eigenschaften in SyncRequest
bieten dieselben Funktionen wie die vorhandenen ContentProvider
-Synchronisierungsaufrufe. Sie können aber zusätzlich festlegen, dass eine Synchronisierung abgebrochen werden soll, wenn das Netzwerk kostenpflichtig ist. Dazu aktivieren Sie setDisallowMetered()
.
Nutzereingabe
Neue Sensortypen
Der neue TYPE_GEOMAGNETIC_ROTATION_VECTOR
-Sensor stellt Rotationsvektordaten auf der Grundlage eines Magnetometers bereit. Dies ist eine nützliche Alternative zum TYPE_ROTATION_VECTOR
-Sensor, wenn kein Gyroskop verfügbar ist oder wenn aufeinanderfolgende Sensorereignisse verwendet werden, um die Ausrichtung des Geräts im Ruhezustand zu erfassen. Dieser Sensor benötigt weniger Strom als TYPE_ROTATION_VECTOR
, ist aber anfällig für verrauschte Ereignisdaten und funktioniert am effektivsten, wenn sich der Nutzer im Freien aufhält.
Android unterstützt jetzt auch in der Hardware integrierte Schrittsensoren:
TYPE_STEP_DETECTOR
- Dieser Sensor löst jedes Mal ein Ereignis aus, wenn der Nutzer einen Schritt macht. Bei jedem Nutzerschritt sendet dieser Sensor ein Ereignis mit dem Wert 1,0 und einem Zeitstempel, der angibt, wann der Schritt erfolgt ist.
TYPE_STEP_COUNTER
- Dieser Sensor löst auch bei jedem erkannten Schritt ein Ereignis aus, sendet aber stattdessen die Gesamtzahl der Schritte, die seit der ersten Registrierung durch eine App erfasst wurden.
Beachten Sie, dass diese beiden Schrittsensoren nicht immer die gleichen Ergebnisse liefern. Die TYPE_STEP_COUNTER
-Ereignisse treten mit einer höheren Latenz auf als die von TYPE_STEP_DETECTOR
. Das liegt daran, dass der TYPE_STEP_COUNTER
-Algorithmus mehr Daten verarbeitet, um falsch positive Ergebnisse zu vermeiden. Daher kann TYPE_STEP_COUNTER
länger dauern, um Ereignisse zu übermitteln, aber die Ergebnisse sollten genauer sein.
Beide Schrittsensoren sind hardwareabhängig (Nexus 5 ist das erste Gerät, das sie unterstützt). Deshalb solltest du mit den Konstanten FEATURE_SENSOR_STEP_DETECTOR
und FEATURE_SENSOR_STEP_COUNTER
die Verfügbarkeit bei hasSystemFeature()
prüfen.
Aufeinanderfolgende Sensorereignisse
Zur besseren Verwaltung der Geräteleistung kannst du über die SensorManager
APIs jetzt die Häufigkeit festlegen, mit der das System Sensorereignisse Batches an deine App senden soll. Dadurch wird nicht die Anzahl der tatsächlich für deine App verfügbaren Sensorereignisse für einen bestimmten Zeitraum reduziert, sondern stattdessen die Häufigkeit reduziert, mit der das System SensorEventListener
über Sensorupdates aufruft. Anstatt jedes Ereignis an Ihre App zu senden, sobald es eintritt, speichert das System alle Ereignisse, die über einen bestimmten Zeitraum auftreten, und sendet sie dann gleichzeitig an Ihre App.
Für die Batch-Verarbeitung fügt die SensorManager
-Klasse zwei neue Versionen der registerListener()
-Methode hinzu, mit denen Sie die maximale Berichtslatenz festlegen können. Dieser neue Parameter gibt die maximale Verzögerung an, die dein SensorEventListener
für die Übermittlung neuer Sensorereignisse toleriert. Wenn Sie beispielsweise eine Batchlatenz von einer Minute angeben, sendet das System die letzten Batchereignisse in einem Intervall von maximal einer Minute durch aufeinanderfolgende Aufrufe der Methode onSensorChanged()
– einmal für jedes Ereignis, für das ein Batch ausgeführt wurde. Die Sensorereignisse werden nie länger als der maximale Latenzwert für Berichte verzögert. Sie können jedoch früher eintreffen, wenn andere Apps für denselben Sensor eine kürzere Latenz angefordert haben.
Beachten Sie jedoch, dass der Sensor die zusammengefassten Ereignisse basierend auf der Latenz des Berichts an Ihre App nur dann sendet, wenn die CPU aktiv ist. Ein Hardwaresensor, der die Batchverarbeitung unterstützt, erfasst zwar weiterhin Sensorereignisse, während sich die CPU im Ruhemodus befindet. Die CPU wird jedoch nicht aktiviert, um die zusammengefassten Ereignisse an Ihre App zu senden. Wenn der Speicher für Ereignisse des Sensors irgendwann aufgebraucht ist, werden die ältesten Ereignisse gelöscht, um die neuesten Ereignisse zu speichern. Ereignisse lassen sich vermeiden, indem das Gerät aktiviert wird, bevor der Sensor den Arbeitsspeicher ausfüllt, und dann flush()
aufrufen, um die letzten Ereignisse zu erfassen. Um abzuschätzen, wann der Speicher voll ist und geleert werden sollte, rufen Sie getFifoMaxEventCount()
auf, um die maximale Anzahl der Sensorereignisse zu erhalten, die gespeichert werden können. Teilen Sie diese Zahl durch die Häufigkeit, mit der jedes Ereignis von der App angefordert wird. Verwende diese Berechnung, um Weckalarme mit AlarmManager
einzustellen, die dein Service
aufrufen (wodurch die SensorEventListener
implementiert wird), um den Sensor zu spülen.
Hinweis:Die Batchverarbeitung von Sensorereignissen wird nicht von allen Geräten unterstützt, da dies vom Hardwaresensor unterstützt werden muss. Ab Android 4.4 sollten Sie jedoch immer die neuen registerListener()
-Methoden verwenden. Wenn das Gerät keine Batchverarbeitung unterstützt, ignoriert das System das Batch-Latenzargument ordnungsgemäß und sendet Sensorereignisse in Echtzeit.
Controller-Identitäten
Android identifiziert nun jeden verbundenen Controller mit einer eindeutigen Ganzzahl, die du mit getControllerNumber()
abfragen kannst. So kannst du jeden Controller einfacher mit einem anderen Spieler in einem Spiel verknüpfen. Die Nummer jedes Controllers kann sich ändern, wenn die Controller vom Nutzer getrennt, verbunden oder neu konfiguriert werden. Sie sollten also verfolgen, welche Controller-Nummer dem jeweiligen Eingabegerät entspricht, indem Sie eine Instanz von InputManager.InputDeviceListener
registrieren. Rufen Sie dann getControllerNumber()
für jede InputDevice
auf, wenn eine Änderung auftritt.
Verbundene Geräte stellen jetzt außerdem Produkt- und Anbieter-IDs bereit, die von getProductId()
und getVendorId()
verfügbar sind. Wenn Sie Ihre Schlüsselzuordnungen basierend auf dem auf einem Gerät verfügbaren Schlüsselsatz ändern müssen, können Sie das Gerät abfragen, um zu prüfen, ob bestimmte Schlüssel mit hasKeys(int...)
verfügbar sind.
Benutzeroberfläche
Immersiver Vollbildmodus
Um für deine App ein Layout bereitzustellen, das den gesamten Bildschirm ausfüllt, aktiviert das neue Flag SYSTEM_UI_FLAG_IMMERSIVE
für setSystemUiVisibility()
(in Kombination mit SYSTEM_UI_FLAG_HIDE_NAVIGATION
) einen neuen immersiven Vollbildmodus. Auch wenn der immersive Vollbildmodus aktiviert ist, werden für Ihre Aktivität weiterhin alle Touch-Ereignisse erfasst. Der Nutzer kann die Systemleisten wieder anzeigen, indem er entlang des Bereichs, in dem die Systemleisten normalerweise erscheinen, nach innen wischt. Dadurch werden das Flag SYSTEM_UI_FLAG_HIDE_NAVIGATION
(und ggf. das Flag SYSTEM_UI_FLAG_FULLSCREEN
) gelöscht, sodass die Systemleisten sichtbar bleiben. Wenn Sie jedoch möchten, dass die Systemleisten nach kurzer Zeit wieder ausgeblendet werden, können Sie stattdessen das Flag SYSTEM_UI_FLAG_IMMERSIVE_STICKY
verwenden.
Durchsichtige Systemleisten
Du kannst die Systemleisten jetzt mit den neuen Designs Theme.Holo.NoActionBar.TranslucentDecor
und Theme.Holo.Light.NoActionBar.TranslucentDecor
teilweise durchscheinen. Wenn Sie durchscheinende Systemleisten aktivieren, füllt Ihr Layout den Bereich hinter den Systemleisten aus. Sie müssen also auch fitsSystemWindows
für den Teil Ihres Layouts aktivieren, der nicht von den Systemleisten abgedeckt werden soll.
Wenn Sie ein benutzerdefiniertes Design erstellen, legen Sie eines dieser Designs als übergeordnetes Design fest oder binden Sie die Stileigenschaften windowTranslucentNavigation
und windowTranslucentStatus
in Ihr Design ein.
Verbesserter Benachrichtigungs-Listener
Unter Android 4.3 wurden die NotificationListenerService
APIs hinzugefügt. Dadurch können Apps Informationen über neue Benachrichtigungen erhalten, sobald diese vom System veröffentlicht werden. In Android 4.4 können Benachrichtigungs-Listener zusätzliche Metadaten für die Benachrichtigung und vollständige Details zu den Aktionen der Benachrichtigung abrufen:
Das neue Feld Notification.extras
enthält einen Bundle
, über den dem Notification Builder zusätzliche Metadaten wie EXTRA_TITLE
und EXTRA_PICTURE
gesendet werden.
Die neue Notification.Action
-Klasse definiert die Eigenschaften einer mit der Benachrichtigung verknüpften Aktion, die Sie aus dem neuen actions
-Feld abrufen können.
Drawable-Spiegelung für RTL-Layouts
In früheren Android-Versionen musst du das gespiegelte Bild in ein drawables-ldrtl/
-Ressourcenverzeichnis einfügen, wenn deine App Bilder enthält, deren horizontale Ausrichtung für von rechts nach links angeordnete Layouts umgekehrt werden sollte. Jetzt kann das System Bilder automatisch für dich spiegeln, indem das autoMirrored
-Attribut für eine Drawable-Ressource aktiviert oder setAutoMirrored()
aufgerufen wird. Wenn diese Option aktiviert ist, wird Drawable
automatisch gespiegelt, wenn die Layoutrichtung von rechts nach links festgelegt ist.
Bedienungshilfen
Mit der Klasse View
kannst du jetzt „Live-Regionen“ für Teile deiner UI deklarieren, die dynamisch mit neuem Textinhalt aktualisiert werden, indem das neue accessibilityLiveRegion
-Attribut zu deinem XML-Layout hinzugefügt oder setAccessibilityLiveRegion()
aufgerufen wird. Beispielsweise sollte ein Anmeldebildschirm mit einem Textfeld, in dem die Benachrichtigung „Falsches Passwort“ angezeigt wird, als Live-Bereich gekennzeichnet werden, damit der Screenreader die Nachricht wiedergibt, wenn sie geändert wird.
Die Funktionen von Apps mit Bedienungshilfen können jetzt auch mit neuen APIs erweitert werden, die Informationen zu Ansichtssammlungen wie Listen- oder Rasteransichten mithilfe von AccessibilityNodeInfo.CollectionInfo
und AccessibilityNodeInfo.CollectionItemInfo
enthalten.
App-Berechtigungen
Die folgenden neuen Berechtigungen müssen von Ihrer App mit dem Tag <uses-permission>
angefordert werden, um bestimmte neue APIs verwenden zu können:
INSTALL_SHORTCUT
- Ermöglicht einer App, eine Verknüpfung im Launcher zu installieren
UNINSTALL_SHORTCUT
- Ermöglicht einer App, eine Verknüpfung im Launcher zu deinstallieren
TRANSMIT_IR
- Ermöglicht einer App die Nutzung des IR-Senders des Geräts, falls verfügbar
Hinweis:Ab Android 4.4 ist es für die Plattform nicht mehr erforderlich, dass deine App WRITE_EXTERNAL_STORAGE
oder READ_EXTERNAL_STORAGE
abruft, wenn du mit Methoden wie getExternalFilesDir()
auf deine app-spezifischen Regionen des externen Speichers zugreifen möchtest. Die Berechtigungen sind jedoch weiterhin erforderlich, wenn Sie auf die gemeinsam nutzbaren Regionen des externen Speichers von getExternalStoragePublicDirectory()
zugreifen möchten.
Gerätefunktionen
Die folgenden neuen Gerätefunktionen können Sie mit dem Tag <uses-feature>
deklarieren, um Ihre App-Anforderungen zu deklarieren und Filter bei Google Play zu aktivieren oder sie zur Laufzeit zu prüfen:
FEATURE_CONSUMER_IR
- Das Gerät kann mit Infrarot-Geräten von Verbrauchern kommunizieren.
FEATURE_DEVICE_ADMIN
- Das Gerät unterstützt die Erzwingung von Geräterichtlinien durch Geräteadministratoren.
FEATURE_NFC_HOST_CARD_EMULATION
- Das Gerät unterstützt die hostbasierte NFC-Kartenemulation.
FEATURE_SENSOR_STEP_COUNTER
- Das Gerät verfügt über einen Hardwareschrittzähler.
FEATURE_SENSOR_STEP_DETECTOR
- Das Gerät verfügt über einen Hardwareschrittdetektor.
Eine detaillierte Ansicht aller API-Änderungen in Android 4.4 finden Sie im Bericht zu API-Unterschieden.