API-Level: 19
Android 4.4 (KITKAT
) ist eine neue Version der Android-Plattform mit neuen Funktionen für Nutzer und App-Entwickler. In diesem Dokument finden Sie eine Einführung in die wichtigsten neuen APIs.
Als App-Entwickler sollten Sie das Android 4.4-Systemimage und die SDK-Plattform so bald wie möglich über den SDK Manager herunterladen. Wenn Sie kein Gerät mit Android 4.4 haben, auf dem Sie Ihre App testen können, verwenden Sie das Android 4.4-System-Image, um Ihre App im Android-Emulator zu testen. Erstellen Sie dann Ihre Apps für die Android 4.4-Plattform, um die neuesten APIs zu verwenden.
Ziel-API-Level aktualisieren
Wenn Sie Ihre App für Geräte mit Android 4.4 optimieren möchten, sollten Sie targetSdkVersion
auf "19"
festlegen, sie auf einem Android 4.4-System-Image installieren, testen und dann ein Update mit dieser Änderung veröffentlichen.
Sie können APIs in Android 4.4 verwenden und gleichzeitig ältere Versionen unterstützen, indem Sie Ihrem Code Bedingungen hinzufügen, die die System-API-Ebene prüfen, bevor APIs ausgeführt werden, die von Ihrer minSdkVersion
nicht unterstützt werden.
Weitere Informationen zur Abwärtskompatibilität finden Sie im Hilfeartikel Unterstützung verschiedener Plattformversionen.
Weitere Informationen zur Funktionsweise von API-Levels finden Sie unter Was ist eine API-Ebene?
Wichtige Änderungen am Verhalten
Wenn Sie bereits eine App für Android veröffentlicht haben, kann es sein, dass sich die Änderungen in Android 4.4 auf Ihre App auswirken.
Wenn Ihre App Daten aus dem externen Speicher liest…
Ihre App kann freigegebene Dateien im externen Speicher nicht lesen, wenn sie unter Android 4.4 ausgeführt wird, es sei denn, Ihre App hat die Berechtigung READ_EXTERNAL_STORAGE
. Das bedeutet, dass auf Dateien im von getExternalStoragePublicDirectory()
zurückgegebenen Verzeichnis ohne die Berechtigung nicht mehr zugegriffen werden kann. Wenn Sie jedoch nur auf Ihre app-spezifischen Verzeichnisse zugreifen müssen, die von getExternalFilesDir()
bereitgestellt werden, benötigen Sie die Berechtigung READ_EXTERNAL_STORAGE
nicht.
Wenn Ihre App WebView verwendet…
Ihre App verhält sich unter Android 4.4 möglicherweise anders, insbesondere wenn Sie die targetSdkVersion
Ihrer App auf „19“ oder höher aktualisieren.
Der Code, der der WebView
-Klasse und den zugehörigen APIs zugrunde liegt, wurde auf einen modernen Snapshot des Chromium-Quellcodes umgestellt. Das bringt eine Vielzahl von Leistungsverbesserungen, die Unterstützung neuer HTML5-Funktionen und die Unterstützung für die Remote-Fehlerbehebung bei WebView
-Inhalten mit sich. Aufgrund des Umfangs dieses Upgrades kann sich das Verhalten Ihrer App in einigen Fällen ändern, wenn Sie WebView
verwenden. Bekannte Verhaltensänderungen sind dokumentiert und wirken sich in der Regel nur dann auf Ihre App aus, wenn Sie die targetSdkVersion
Ihrer App auf „19“ oder höher aktualisieren. Die neue WebView
arbeitet im „Kompatibilitätsmodus“, um einige ältere Funktionen in Apps bereitzustellen, die auf API-Ebene 18 oder niedriger ausgerichtet sind. Es ist jedoch möglich, dass Ihre App von unbekannten Verhaltensweisen der vorherigen Version von WebView
abhängt.
Wenn Ihre vorhandene App WebView
verwendet, sollten Sie sie so bald wie möglich unter Android 4.4 testen. Weitere Informationen dazu, wie sich die Aktualisierung von targetSdkVersion
auf „19“ oder höher auf Ihre App auswirken kann, finden Sie unter Zur WebView-Migration in Android 4.4.
Wenn Ihre App AlarmManager verwendet:
Wenn Sie die targetSdkVersion
Ihrer App auf „19“ oder höher festlegen, sind Wecker, die Sie mit set()
oder setRepeating()
erstellen, ungenau.
Zur Verbesserung der Energieeffizienz werden Wecker von allen Apps, die ungefähr zur selben Zeit klingeln, jetzt in Android gruppiert. So muss das System das Gerät nicht mehr mehrmals, sondern nur einmal aufwecken, um jeden Wecker zu bearbeiten.
Wenn Ihr Wecker nicht mit einer genauen Uhrzeit verknüpft ist, es aber wichtig ist, dass er in einem bestimmten Zeitraum ausgelöst wird (z. B. zwischen 14:00 und 16:00 Uhr), können Sie die neue Methode setWindow()
verwenden. Dabei wird eine „früheste“ Uhrzeit für den Wecker und ein „Zeitfenster“ nach der frühesten Uhrzeit angegeben, innerhalb derer der Wecker vom System ausgelöst werden soll.
Wenn Ihr Wecker auf eine genaue Uhrzeit festgelegt werden muss (z. B. für eine Erinnerung an einen Kalendertermin), können Sie die neue Methode setExact()
verwenden.
Dieses ungenaue Batching-Verhalten gilt nur für aktualisierte Apps. Wenn Sie targetSdkVersion
auf „18“ oder niedriger festgelegt haben, verhalten sich Ihre Wecker unter Android 4.4 weiterhin wie in früheren Versionen.
Wenn Ihre App Daten mit ContentResolver synchronisiert…
Wenn Sie targetSdkVersion
Ihrer App auf „19“ oder höher festlegen, werden bei der Synchronisierung mit addPeriodicSync()
die Synchronisierungsvorgänge innerhalb eines standardmäßigen flexiblen Intervalls von etwa 4% des angegebenen Zeitraums ausgeführt. Wenn die Abfragehäufigkeit beispielsweise 24 Stunden beträgt, kann die Synchronisierung jeden Tag innerhalb eines Zeitfensters von etwa einer Stunde erfolgen, anstatt jeden Tag genau zur selben Zeit.
Wenn du ein eigenes Flex-Intervall für Synchronisierungsvorgänge angeben möchtest, solltest du die neue requestSync()
-Methode verwenden. Weitere Informationen finden Sie im Abschnitt unten unter Synchronisierungsadapter.
Dieses Flex-Intervall-Verhalten gilt nur für aktualisierte Apps. Wenn Sie targetSdkVersion
auf „18“ oder niedriger festgelegt haben, verhalten sich Ihre vorhandenen Synchronisierungsanfragen unter Android 4.4 weiterhin wie in früheren Versionen.
Druck-Framework
Android enthält jetzt ein vollständiges Framework, mit dem Nutzer jedes Dokument über einen Drucker drucken können, der über WLAN, Bluetooth oder andere Dienste verbunden ist. 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 bietet alle APIs, die zum Angeben eines Druckdokuments und zum Senden an das System zum Drucken erforderlich sind. Welche APIs Sie für einen bestimmten Druckauftrag tatsächlich benötigen, hängt von Ihren Inhalten ab.
Allgemeine Inhalte drucken
Wenn Sie Inhalte aus Ihrer Benutzeroberfläche als Dokument drucken möchten, müssen Sie zuerst eine Unterklasse von PrintDocumentAdapter
erstellen. In dieser Klasse müssen Sie einige Rückrufmethoden implementieren, darunter onLayout()
, um das Layout anhand der angegebenen Druckeigenschaften festzulegen, und onWrite()
, um die druckbaren Inhalte in eine ParcelFileDescriptor
zu serialisieren.
Damit Sie Ihre Inhalte in die ParcelFileDescriptor
schreiben können, müssen Sie ihr eine PDF-Datei übergeben. Die neuen PdfDocument
APIs bieten eine praktische Möglichkeit, indem sie eine Canvas
von getCanvas()
bereitstellen, auf der Sie Ihre druckbaren Inhalte zeichnen können. Schreiben Sie dann die PdfDocument
mit der Methode writeTo()
in die ParcelFileDescriptor
.
Nachdem Sie Ihre Implementierung für PrintDocumentAdapter
definiert haben, können Sie Druckjobs auf Anfrage des Nutzers mit der PrintManager
-Methode print()
ausführen, die PrintDocumentAdapter
als eines ihrer Argumente verwendet.
Bilder drucken
Wenn Sie nur ein Foto oder eine andere Bitmap drucken möchten, erledigen die Hilfs-APIs in der Supportbibliothek die gesamte Arbeit für Sie. Erstellen Sie einfach eine neue Instanz von PrintHelper
, legen Sie den Skalierungsmodus mit setScaleMode()
fest und übergeben Sie Bitmap
an printBitmap()
. Das wars. Die Bibliothek übernimmt alle verbleibenden Interaktionen mit dem System, um die Bitmap an den Drucker zu senden.
Druckdienste für Gebäude
Als Drucker-OEM können Sie das android.printservice
-Framework verwenden, um die Interoperabilität mit Ihren Druckern von Android-Geräten 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 hauptsächlich als headless-Dienst ausgeführt, indem die Klasse PrintService
als Unterklasse definiert wird. Diese Klasse empfängt Druckjobs vom System und sendet sie über die entsprechenden Protokolle an die Drucker.
Weitere Informationen zum Drucken von App-Inhalten finden Sie unter Inhalte drucken.
SMS-Anbieter
Der Telephony
-Inhaltsanbieter (der „SMS-Anbieter“) ermöglicht Apps, SMS- und MMS-Nachrichten auf dem Gerät zu lesen und zu schreiben. Sie enthält unter anderem Tabellen für empfangene, verfasste, gesendete und ausstehende SMS und MMS.
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 auf den SMS-Anbieter schreiben und nur die Standard-SMS-App empfängt die SMS_DELIVER_ACTION
-Broadcasts, wenn der Nutzer eine SMS erhält, oder die WAP_PUSH_DELIVER_ACTION
-Broadcasts, wenn der Nutzer eine MMS erhält. Die Standard-SMS-App ist dafür verantwortlich, Details an den SMS-Anbieter zu senden, wenn eine neue Nachricht empfangen oder gesendet wird.
Andere Apps, die nicht als Standard-SMS-App ausgewählt sind, können nur den SMS-Anbieter lesen, aber auch benachrichtigt werden, wenn eine neue SMS eingeht. Dazu wird der SMS_RECEIVED_ACTION
-Broadcast überwacht, ein nicht abbruchbarer Broadcast, der an mehrere Apps gesendet werden kann. Diese Broadcasts sind für Apps gedacht, die zwar nicht als Standard-SMS-App ausgewählt wurden, aber spezielle eingehende Nachrichten lesen müssen, z. B. für die Bestätigung der Telefonnummer.
Weitere Informationen finden Sie im Blogpost SMS-Apps für KitKat vorbereiten.
WLAN und Konnektivität
Host Card Emulation
Android-Apps können jetzt ISO14443-4-NFC-Karten (ISO-DEP) emulieren, die APDUs für den Datenaustausch verwenden (wie in ISO7816-4 angegeben). So 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 Anwendungs-ID (Application Identifier, AID) initiieren.
Wenn Sie eine NFC-Karte emulieren möchten, die diese Protokolle in Ihrer App verwendet, erstellen Sie eine Dienstkomponente auf der Grundlage der Klasse HostApduService
. Wenn Ihre App stattdessen ein Secure Element für die Kartenemulation verwendet, müssen Sie einen Dienst basierend auf der OffHostApduService
-Klasse erstellen. Dieser ist nicht direkt an den Transaktionen beteiligt, aber erforderlich, um die AIDs zu registrieren, die vom Secure Element verarbeitet werden sollen.
Weitere Informationen finden Sie im Leitfaden zur NFC-Kartenemulation.
NFC-Lesemodus
Mit einem neuen NFC-Lesemodus kann eine Aktivität alle NFC-Aktivitäten darauf beschränken, nur die Tag-Typen zu lesen, die für die Aktivität im Vordergrund relevant sind. Sie können den Reader-Modus für Ihre 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 in Verbindung mit der Host-Kartenemulation ermöglicht es Android, an beiden Enden einer mobilen Zahlungsoberfläche zu arbeiten: Ein Gerät dient als Zahlungsterminal (ein Gerät, auf dem eine Aktivität im Lesemodus ausgeführt wird) und ein anderes Gerät als Zahlungsclient (ein Gerät, das eine NFC-Karte emuliert).
Infrarot-Sender
Wenn Sie die App auf einem Gerät mit Infrarot-Sender ausführen, können Sie jetzt IR-Signale über die ConsumerIrManager
APIs übertragen. Wenn Sie eine Instanz von ConsumerIrManager
abrufen möchten, rufen Sie getSystemService()
mit CONSUMER_IR_SERVICE
als Argument auf. Sie können dann mit getCarrierFrequencies()
die unterstützten IR-Frequenzen des Geräts abfragen und Signale übertragen, indem Sie die gewünschte Frequenz und das gewünschte Signalmuster mit transmit()
übergeben.
Sie sollten immer zuerst prüfen, ob ein Gerät einen IR-Sender hat, indem Sie hasIrEmitter()
aufrufen. Wenn Ihre App jedoch nur mit Geräten kompatibel ist, die einen IR-Sender haben, sollten Sie in Ihrem Manifest ein <uses-feature>
-Element für "android.hardware.consumerir"
(FEATURE_CONSUMER_IR
) einfügen.
Multimedia
Adaptive Wiedergabe
Die MediaCodec
APIs unterstützen jetzt die adaptive Videowiedergabe. So kann die Auflösung während der Wiedergabe auf einem Surface
nahtlos geändert werden. Du kannst dem Decoder Eingabeframes mit einer neuen Auflösung zuführen und die Auflösung der Ausgabebuffer ändert sich ohne große Lücke.
Sie können die adaptive Wiedergabe aktivieren, indem Sie MediaFormat
zwei Schlüssel hinzufügen, die die maximale Auflösung angeben, die Ihre App vom Codec benötigt: KEY_MAX_WIDTH
und KEY_MAX_HEIGHT
. Nachdem du diese deinem MediaFormat
hinzugefügt hast, kannst du MediaFormat
mit configure()
an deine MediaCodec
-Instanz übergeben.
Der Codec wechselt nahtlos zwischen Auflösungen, die mit diesen Werten übereinstimmen oder kleiner sind. Der Codec unterstützt möglicherweise auch Auflösungen, die über den angegebenen Maximalwerten liegen, solange sie innerhalb der Grenzen der unterstützten Profile liegen. Die Übergänge zu höheren Auflösungen sind jedoch möglicherweise nicht reibungslos.
Wenn Sie die Auflösung beim Decodieren von H.264-Videos ändern möchten, setzen Sie die Frames mit MediaCodec.queueInputBuffer() weiterhin in die Warteschlange. Achten Sie aber darauf, die neuen SPS- (Sequence Parameter Set) und PPS-Werte (Picture Parameter Set) zusammen mit dem IDR-Frame (Instantaneous Decoder Refresh) in einem einzigen Puffer anzugeben.
Bevor du deinen Codec jedoch für die adaptive Wiedergabe konfigurierst, 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 für die adaptive Wiedergabe ist anbieterspezifisch. Für einige Codecs ist bei größeren Auflösungshinweise möglicherweise mehr Arbeitsspeicher erforderlich. Daher solltest du die maximalen Auflösungen anhand des decodierten Quellmaterials festlegen.
Zeitstempel für On-Demand-Audio
Zur Vereinfachung der Audio-Video-Synchronisierung enthält die neue AudioTimestamp
-Klasse Zeitachsendetails zu einem bestimmten Frame in einem Audiostream, der von AudioTrack
verarbeitet wird. Wenn du den neuesten verfügbaren Zeitstempel abrufen möchtest, musst du ein AudioTimestamp
-Objekt instanziieren und an getTimestamp()
übergeben. Wenn die Anfrage nach dem Zeitstempel erfolgreich ist, wird die AudioTrack
-Instanz mit einer Position in Frame-Einheiten sowie der geschätzten Zeit ausgefüllt, zu der dieser Frame entweder präsentiert wurde oder präsentiert werden soll.
Du kannst den Wert von nanoTime
in AudioTimestamp
(der monoton ist) verwenden, um den am nächsten gelegenen zugehörigen Videoframe zu framePosition
zu finden. So kannst du Videoframes einfügen, duplizieren oder interpolieren, um sie an den Audiotrack anzupassen. Alternativ kannst du 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 zum selben Zeitpunkt wie ein Videoframe erwartet wird.
Oberflächenbildlesegerät
Die neue ImageReader
API bietet direkten Zugriff auf Bildbuffer, während sie in ein Surface
gerendert werden. Sie können eine ImageReader
mit der statischen Methode newInstance()
abrufen. Rufe dann getSurface()
auf, um eine neue Surface
zu erstellen, und übermittle deine Bilddaten mit einem Producer wie MediaPlayer
oder MediaCodec
. Wenn Sie benachrichtigt werden möchten, wenn neue Bilder auf der Oberfläche verfügbar sind, implementieren Sie die ImageReader.OnImageAvailableListener
-Schnittstelle und registrieren Sie sie bei setOnImageAvailableListener()
.
Wenn du jetzt Inhalte in Surface
zeichnest, erhält ImageReader.OnImageAvailableListener
bei jedem neuen Bildframe einen Aufruf an onImageAvailable()
, der dir die entsprechende ImageReader
liefert. Sie können die Bilddaten des Frames mit ImageReader
als Image
-Objekt abrufen, indem Sie acquireLatestImage()
oder acquireNextImage()
aufrufen.
Das Image
-Objekt bietet direkten Zugriff auf den Zeitstempel, das Format, die Abmessungen und die Pixeldaten des Bilds in einem ByteBuffer
. Damit die Image
-Klasse Ihre Bilder jedoch interpretieren kann, müssen sie gemäß einem der Typen formatiert sein, die durch Konstanten in ImageFormat
oder PixelFormat
definiert sind.
Spitzen- und RMS-Messung
Du kannst jetzt den Spitzen- und RMS-Wert des aktuellen Audiostreams von Visualizer
abfragen, indem du eine neue Instanz von Visualizer.MeasurementPeakRms
erstellst und an getMeasurementPeakRms()
weitergibst. Wenn Sie diese Methode aufrufen, werden die Spitzen- und RMS-Werte des angegebenen Visualizer.MeasurementPeakRms
auf die zuletzt gemessenen Werte gesetzt.
Lautstärkeverstärkung
LoudnessEnhancer
ist eine neue Unterklasse von AudioEffect
, mit der Sie die hörbare Lautstärke Ihrer MediaPlayer
oder AudioTrack
erhöhen können. Das kann besonders in Verbindung mit der oben genannten neuen getMeasurementPeakRms()
-Methode nützlich sein, um die Lautstärke gesprochener Audiotracks zu erhöhen, während andere Medien gerade wiedergegeben werden.
Fernbedienungen
Mit Android 4.0 (API-Ebene 14) wurden die RemoteControlClient
APIs eingeführt, mit denen Medien-Apps Mediencontroller-Ereignisse von Remote-Clients wie Mediensteuerelemente auf dem Sperrbildschirm nutzen können. Mit den neuen RemoteController
APIs können Sie jetzt Ihre eigene Fernbedienung erstellen und so innovative neue Apps und Peripheriegeräte entwickeln, mit denen sich die Wiedergabe jeder Medien-App steuern lässt, die mit RemoteControlClient
integriert ist.
Wenn Sie eine Fernbedienung erstellen, können Sie Ihre Benutzeroberfläche beliebig implementieren. Wenn Sie die Ereignisse der Medienschaltfläche jedoch an die Medien-App des Nutzers weitergeben möchten, müssen Sie einen Dienst erstellen, der die NotificationListenerService
-Klasse erweitert und die RemoteController.OnClientUpdateListener
-Schnittstelle implementiert. Die Verwendung der NotificationListenerService
als Grundlage ist wichtig, da sie die entsprechenden Datenschutzeinschränkungen bietet, die es Nutzern erfordern, Ihre App in den Systemsicherheitseinstellungen als Benachrichtigungslistener zu aktivieren.
Die Klasse NotificationListenerService
enthält einige abstrakte Methoden, die Sie implementieren müssen. Wenn Sie sich jedoch nur mit den Mediacontroller-Ereignissen zur Verarbeitung der Medienwiedergabe befassen, können Sie die Implementierung für diese Ereignisse 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 (Apps, die Mediensteuerungsereignisse mit der RemoteControlClient
empfangen) auf und bietet Nutzern die Möglichkeit, den aktuellen Titel über die Fernbedienung zu bewerten.
Die neue Klasse Rating
enthält Informationen zu einer Nutzerbewertung. Eine Altersfreigabe wird durch ihren Stil (RATING_HEART
, RATING_THUMB_UP_DOWN
, RATING_3_STARS
, RATING_4_STARS
, RATING_5_STARS
oder RATING_PERCENTAGE
) und den für diesen Stil geeigneten Wert definiert.
So kannst du Nutzern erlauben, deine Titel über eine Fernbedienung zu bewerten:
- Wenn Sie die Bewertungsoberfläche für den Nutzer sichtbar machen möchten, fügen Sie das Flag
FLAG_KEY_MEDIA_RATING
insetTransportControlFlags()
hinzu. - Rufen Sie
editMetadata()
auf, um eineRemoteControlClient.MetadataEditor
abzurufen, und übergeben Sie sieRATING_KEY_BY_USER
mitaddEditableKey()
. - Geben Sie dann den Altersfreigabestil an, indem Sie
putObject()
aufrufen undRATING_KEY_BY_USER
als Schlüssel und einen der oben genannten Altersfreigabestile als Wert übergeben.
Wenn du einen Rückruf erhalten möchtest, wenn der Nutzer die Altersfreigabe über die Fernbedienung ändert, implementiere die neue RemoteControlClient.OnMetadataUpdateListener
-Benutzeroberfläche und übergebe eine Instanz an setMetadataUpdateListener()
. Wenn der Nutzer die Bewertung ändert, wird onMetadataUpdate()
von deinem RemoteControlClient.OnMetadataUpdateListener
aufgerufen. Dabei wird RATING_KEY_BY_USER
als Schlüssel und ein Rating
-Objekt als Wert übergeben.
Untertitel
VideoView
unterstützt jetzt WebVTT-Untertiteltracks beim Abspielen von HTTP-Livestreams (HLS). Die Untertitel werden gemäß den Einstellungen für Untertitel angezeigt, die der Nutzer in den Systemeinstellungen festgelegt hat.
Du kannst VideoView
auch mit deinen WebVTT-Untertiteltracks über die addSubtitleSource()
-Methode versorgen. Diese Methode akzeptiert ein InputStream
, das die Untertiteldaten enthält, und ein MediaFormat
-Objekt, das das Format für die Untertiteldaten angibt. Du kannst das Format mit createSubtitleFormat()
angeben. Diese Untertitel werden je nach den Einstellungen des Nutzers auch über dem Video angezeigt.
Wenn du deine Videoinhalte nicht über VideoView
darstellst, solltest du das Untertitel-Overlay so anpassen, dass es den Untertiteleinstellungen des Nutzers möglichst entspricht. Mit einer neuen CaptioningManager
API kannst du die Untertiteleinstellungen des Nutzers abfragen, einschließlich der von CaptioningManager.CaptionStyle
definierten Stile wie Schriftart und Farbe. Falls der Nutzer einige Einstellungen anpasst, nachdem dein Video bereits gestartet wurde, solltest du auf Änderungen an den Einstellungen achten. Dazu registrierst du eine Instanz von CaptioningManager.CaptioningChangeListener
, um einen Rückruf zu erhalten, wenn sich eine der Einstellungen ändert. Aktualisiere dann deine Untertitel bei Bedarf.
Animation und Grafik
Szenen und Übergänge
Das neue android.transition
-Framework bietet APIs, die Animationen zwischen verschiedenen Status Ihrer Benutzeroberfläche ermöglichen. Ein wichtiges Feature ist die Möglichkeit, verschiedene Zustände Ihrer Benutzeroberfläche zu definieren, die als „Szenen“ bezeichnet werden. Dazu erstellen Sie für jeden Zustand ein separates Layout. Wenn Sie von einer Szene zur nächsten animieren möchten, führen Sie einen „Übergang“ aus. Dabei wird die erforderliche Animation berechnet, um das Layout von der aktuellen Szene in die nächste zu ändern.
Wenn Sie zwischen zwei Szenen wechseln möchten, müssen Sie in der Regel Folgendes tun:
- Geben Sie die
ViewGroup
mit den UI-Komponenten an, die Sie ändern möchten. - Geben Sie das Layout an, das das Endergebnis der Änderung darstellt (die nächste Szene).
- Geben Sie den Übergangstyp an, mit dem die Layoutänderung animiert werden soll.
- Führen Sie die Umstellung aus.
Sie können ein Scene
-Objekt verwenden, um die Schritte 1 und 2 auszuführen. Ein Scene
enthält Metadaten, die die Eigenschaften eines Layouts beschreiben, die für die Ausführung eines Übergangs erforderlich sind, einschließlich der übergeordneten Ansicht und des Layouts der Szene. Sie können ein Scene
mit einem Klassenkonstruktor oder der statischen Methode getSceneForLayout()
erstellen.
Führen Sie dann die Schritte 3 und 4 mit der TransitionManager
aus. Eine Möglichkeit besteht darin, die Scene
an die statische Methode go()
zu übergeben. Dadurch wird die übergeordnete Ansicht der Szene im aktuellen Layout gefunden und ein Übergang zu den untergeordneten Ansichten ausgeführt, um das durch die Scene
definierte Layout zu erreichen.
Alternativ müssen Sie kein Scene
-Objekt erstellen, sondern können stattdessen beginDelayedTransition()
aufrufen und dabei ein ViewGroup
angeben, das die Ansichten enthält, die Sie ändern möchten. Fügen Sie dann die Zielansichten hinzu, entfernen Sie sie oder konfigurieren Sie sie neu. Nachdem das System die Änderungen wie erforderlich vorgenommen hat, beginnt ein Übergang, um alle betroffenen Ansichten zu animieren.
Für eine zusätzliche Steuerung können Sie mithilfe einer XML-Datei im Projektverzeichnis res/transition/
Übergänge definieren, die zwischen vordefinierten Szenen auftreten sollen. Gib innerhalb eines <transitionManager>
-Elements ein oder mehrere <transition>
-Tags an, die jeweils eine Szene (eine Referenz auf eine Layoutdatei) und den Übergang angeben, der beim Betreten und/oder Verlassen dieser Szene angewendet werden soll. Anschließend maximieren Sie diese Übergänge mit inflateTransitionManager()
. Verwende den zurückgegebenen TransitionManager
, um jeden Übergang mit transitionTo()
auszuführen, und übergebe einen Scene
, der durch eines der <transition>
-Tags dargestellt wird. Sie können auch Übergänge mithilfe der TransitionManager
APIs programmatisch definieren.
Wenn Sie einen Übergang angeben, können Sie mehrere vordefinierte Typen verwenden, die durch Unterklassen von Transition
definiert sind, z. B. Fade
und ChangeBounds
. Wenn Sie keinen Übergangstyp angeben, verwendet das System standardmäßig AutoTransition
. Dabei werden Ansichten bei Bedarf automatisch ausgeblendet, verschoben und ihre Größe angepasst. Außerdem können Sie benutzerdefinierte Übergänge erstellen, indem Sie eine dieser Klassen erweitern, um die Animationen nach Belieben auszuführen. Mit einem benutzerdefinierten Übergang können Sie beliebige Property-Änderungen erfassen und basierend auf diesen Änderungen eine beliebige Animation erstellen. Sie können beispielsweise eine Unterklasse von Transition
bereitstellen, die auf Änderungen an der Eigenschaft „rotation“ einer Ansicht achtet und dann alle Änderungen animiert.
Weitere Informationen finden Sie in der TransitionManager
-Dokumentation.
Animator pausieren
Mit den Animator
APIs können Sie jetzt mit den Methoden pause()
und resume()
eine laufende Animation pausieren und fortsetzen.
Wenn Sie den Status einer Animation verfolgen möchten, können Sie die Animator.AnimatorPauseListener
-Benutzeroberfläche implementieren. Sie bietet Callbacks, wenn eine Animation pausiert und fortgesetzt wird: pause()
und resume()
. Fügen Sie den Listener dann einem Animator
-Objekt mit addPauseListener()
hinzu.
Alternativ können Sie eine untergeordnete Klasse der abstrakten Klasse AnimatorListenerAdapter
erstellen, die jetzt leere Implementierungen für die von Animator.AnimatorPauseListener
definierten Callbacks zum Pausieren und Fortsetzen enthält.
Wiederverwendbare Bitmaps
Sie können jetzt jede veränderbare Bitmap in BitmapFactory
wiederverwenden, um eine andere Bitmap zu decodieren – auch wenn die neue Bitmap eine andere Größe hat –, solange die resultierende Byteanzahl der decodierten Bitmap (verfügbar unter getByteCount()
) kleiner oder gleich der zugewiesenen Byteanzahl der wiederverwendeten Bitmap ist (verfügbar unter getAllocationByteCount()
). Weitere Informationen finden Sie unter inBitmap
.
Neue APIs für Bitmap
ermöglichen eine ähnliche Neukonfiguration für die Wiederverwendung außerhalb von BitmapFactory
(für die manuelle Bitmap-Generierung oder benutzerdefinierte Dekodierungslogik). Sie können jetzt die Abmessungen einer Bitmap mit den Methoden setHeight()
und setWidth()
festlegen und eine neue Bitmap.Config
mit setConfig()
angeben, ohne dass sich dies auf die zugrunde liegende Bitmap-Zuweisung auswirkt. Die Methode reconfigure()
bietet auch eine praktische Möglichkeit, diese Änderungen mit einem einzigen Aufruf zu kombinieren.
Sie sollten jedoch keine Bitmap neu konfigurieren, die derzeit vom Ansichtssystem verwendet wird, da der zugrunde liegende Pixelpuffer nicht auf vorhersehbare Weise 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 weiterhin die richtige Methode, um eine Datei anzufordern, die Sie in Ihre App importieren möchten. Mit 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 langfristigen Lesezugriff (ggf. mit Schreibzugriff) auf diese Datei 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 für die Dateiauswahl nutzen, indem Sie einen Inhaltsanbieter als Unterklasse der neuen Klasse DocumentsProvider
implementieren. Ihre abgeleitete Klasse von DocumentsProvider
muss einen Intent-Filter enthalten, der die Aktion PROVIDER_INTERFACE
("android.content.action.DOCUMENTS_PROVIDER"
) akzeptiert. Anschließend müssen Sie die vier abstrakten Methoden in der DocumentsProvider
implementieren:
queryRoots()
- Dabei muss eine
Cursor
zurückgegeben werden, die alle Stammverzeichnisse Ihres Dokumentenspeichers mithilfe der inDocumentsContract.Root
definierten Spalten beschreibt. queryChildDocuments()
- Dabei muss eine
Cursor
zurückgegeben werden, die alle Dateien im angegebenen Verzeichnis mithilfe der inDocumentsContract.Document
definierten Spalten beschreibt. queryDocument()
- Dabei muss eine
Cursor
zurückgegeben werden, die die angegebene Datei mithilfe der inDocumentsContract.Document
definierten Spalten beschreibt. openDocument()
- Dabei muss eine
ParcelFileDescriptor
zurückgegeben werden, die die angegebene Datei darstellt. Das System ruft diese Methode auf, wenn der Nutzer eine Datei auswählt und die Client-App durch Aufrufen vonopenFileDescriptor()
Zugriff darauf anfordert.
Weitere Informationen finden Sie im Leitfaden zum Storage Access Framework.
Zugriff auf externen Speicher
Sie können jetzt appspezifische 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 einen der von dieser Methode zurückgegebenen Pfade lesen oder darauf schreiben, übergeben Sie das File
-Objekt an die neue getStorageState()
-Methode, um zu prüfen, ob der Speicherplatz derzeit verfügbar ist.
Für andere Methoden zum Zugriff auf das app-spezifische Cache-Verzeichnis und das OBB-Verzeichnis gibt es jetzt auch entsprechende Versionen, die den Zugriff auf sekundäre Speichergeräte ermöglichen: getExternalCacheDirs()
und getObbDirs()
.
Der erste Eintrag im zurückgegebenen File
-Array gilt als primärer externer Speicher des Geräts. Er entspricht dem File
, der von vorhandenen Methoden wie getExternalFilesDir()
zurückgegeben wird.
Hinweis:Ab Android 4.4 muss Ihre App die WRITE_EXTERNAL_STORAGE
oder READ_EXTERNAL_STORAGE
nicht mehr abrufen, wenn Sie mit den oben genannten Methoden nur auf Ihre app-spezifischen Bereiche des externen Speichers zugreifen müssen. Die Berechtigungen sind jedoch erforderlich, wenn Sie auf die freigegebenen Bereiche des externen Speichers zugreifen möchten, die von getExternalStoragePublicDirectory()
bereitgestellt werden.
Synchronisierungsadapter
Die neue Methode requestSync()
in ContentResolver
vereinfacht das Definieren einer Synchronisierungsanfrage für Ihre ContentProvider
, da Anfragen im neuen SyncRequest
-Objekt gekapselt werden, das Sie mit SyncRequest.Builder
erstellen können. Die Eigenschaften in SyncRequest
bieten dieselben Funktionen wie die vorhandenen ContentProvider
-Synchronisierungsaufrufe. Sie können jedoch angeben, dass eine Synchronisierung beendet werden soll, wenn das Netzwerk getaktet ist, indem Sie setDisallowMetered()
aktivieren.
Nutzereingabe
Neue Sensortypen
Der neue TYPE_GEOMAGNETIC_ROTATION_VECTOR
-Sensor liefert Rotationsvektordaten auf der Grundlage eines Magnetometers. Dies ist eine nützliche Alternative zum TYPE_ROTATION_VECTOR
-Sensor, wenn kein Gyroskop verfügbar ist, oder wenn er mit Batch-Sensorereignissen verwendet wird, um die Ausrichtung des Geräts zu erfassen, während das Smartphone inaktiv ist. Dieser Sensor benötigt weniger Strom als TYPE_ROTATION_VECTOR
, kann aber anfällig für fehlerhafte Ereignisdaten sein und ist am effektivsten, wenn sich der Nutzer im Freien befindet.
Android unterstützt jetzt auch integrierte Schrittzähler in der Hardware:
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 ausgeführt wurde.
TYPE_STEP_COUNTER
- Dieser Sensor löst auch bei jedem erkannten Schritt ein Ereignis aus, liefert aber stattdessen die Gesamtzahl der Schritte seit der Erstregistrierung dieses Sensors durch eine App.
Beachten Sie, dass diese beiden Schrittsensoren nicht immer dieselben 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 Verarbeitungen durchführt, um falsch positive Ergebnisse zu vermeiden. Die Übermittlung von Ereignissen über die TYPE_STEP_COUNTER
kann also länger dauern, die Ergebnisse sollten aber genauer sein.
Beide Schrittsensoren sind hardwareabhängig (Nexus 5 ist das erste Gerät, das sie unterstützt). Sie sollten daher mit hasSystemFeature()
und den Konstanten FEATURE_SENSOR_STEP_DETECTOR
und FEATURE_SENSOR_STEP_COUNTER
die Verfügbarkeit prüfen.
Batch-Sensorereignisse
Um die Geräteleistung besser zu verwalten, können Sie mit den SensorManager
APIs jetzt angeben, wie oft das System Sensorereignisse an Ihre App senden soll. Dadurch wird nicht die Anzahl der tatsächlichen Sensorereignisse reduziert, die Ihrer App für einen bestimmten Zeitraum zur Verfügung stehen, sondern die Häufigkeit, mit der das System Ihre SensorEventListener
mit Sensoraktualisierungen aufruft. Anstatt jedes Ereignis sofort an Ihre App zu senden, speichert das System alle Ereignisse, die über einen bestimmten Zeitraum auftreten, und sendet sie dann gleichzeitig an Ihre App.
Für die Batchverarbeitung werden in der SensorManager
-Klasse zwei neue Versionen der registerListener()
-Methode hinzugefügt, mit denen Sie die „maximale Berichtslatenz“ angeben können. Mit diesem neuen Parameter wird die maximale Verzögerung angegeben, die Ihre SensorEventListener
für die Übermittlung neuer Sensorereignisse toleriert. Wenn Sie beispielsweise eine Batch-Latenz von einer Minute angeben, liefert das System die letzten Batch-Ereignisse in einem Intervall von maximal einer Minute, indem die onSensorChanged()
-Methode nacheinander aufgerufen wird – einmal für jedes Ereignis, das im Batch zusammengefasst wurde. Die Sensorereignisse werden nie länger verzögert als der Wert für die maximale Berichtslatenz. Sie können aber früher eintreffen, wenn andere Apps für denselben Sensor eine kürzere Latenz angefordert haben.
Beachten Sie jedoch, dass der Sensor die Batch-Ereignisse basierend auf Ihrer Berichtslatenz nur sendet, wenn die CPU aktiv ist. Ein Hardwaresensor, der Batching unterstützt, erfasst zwar weiterhin Sensorereignisse, während die CPU inaktiv ist, weckt die CPU aber nicht auf, um die Batch-Ereignisse an Ihre App zu senden. Wenn der Sensor nicht mehr genügend Arbeitsspeicher für Ereignisse hat, werden die ältesten Ereignisse gelöscht, um die neuesten Ereignisse zu speichern. Sie können verhindern, dass Ereignisse verloren gehen, indem Sie das Gerät aufwecken, bevor der Sensor seinen Speicher füllt, und dann flush()
aufrufen, um die neuesten Ereignisse zu erfassen. Wenn Sie abschätzen möchten, 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, und teilen Sie diese Zahl durch die Rate, mit der Ihre App jedes Ereignis benötigt. Verwenden Sie diese Berechnung, um Wecker mit AlarmManager
zu stellen, die Ihren Service
(der die SensorEventListener
implementiert) aufrufen, um den Sensor zu löschen.
Hinweis:Nicht alle Geräte unterstützen das Batching von Sensorereignissen, 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 das Batching nicht unterstützt, ignoriert das System das Argument für die Batch-Latenz und liefert Sensorereignisse in Echtzeit.
Controller-Identitäten
Android identifiziert jetzt jeden verbundenen Controller mit einer eindeutigen Ganzzahl, die Sie mit getControllerNumber()
abfragen können. So können Sie jeden Controller einem anderen Spieler in einem Spiel zuordnen. Die Nummer für jeden Controller kann sich ändern, da Controller vom Nutzer getrennt, verbunden oder neu konfiguriert werden. Sie sollten daher verfolgen, welche Controllernummer welchem Eingabegerät entspricht, indem Sie eine Instanz von InputManager.InputDeviceListener
registrieren. Rufen Sie dann getControllerNumber()
für jede InputDevice
auf, wenn eine Änderung eintritt.
Verbundene Geräte bieten jetzt auch Produkt- und Anbieter-IDs, die über getProductId()
und getVendorId()
verfügbar sind. Wenn Sie die Tastenzuordnungen basierend auf den verfügbaren Tasten auf einem Gerät ändern müssen, können Sie das Gerät mit hasKeys(int...)
abfragen, um zu prüfen, ob bestimmte Tasten verfügbar sind.
Benutzeroberfläche
Vollbildmodus
Wenn Sie Ihrer App ein Layout geben möchten, das den gesamten Bildschirm ausfüllt, können Sie mit dem neuen Flag SYSTEM_UI_FLAG_IMMERSIVE
für setSystemUiVisibility()
(in Kombination mit SYSTEM_UI_FLAG_HIDE_NAVIGATION
) einen neuen immersiven Vollbildmodus aktivieren. Wenn der immersive Vollbildmodus aktiviert ist, werden alle Touch-Ereignisse weiterhin für Ihre Aktivität erfasst. Der Nutzer kann die Systemleisten wieder anzeigen, indem er entlang des Bereichs, in dem die Systemleisten normalerweise erscheinen, nach innen wischt. Dadurch wird das Flag SYSTEM_UI_FLAG_HIDE_NAVIGATION
(und das Flag SYSTEM_UI_FLAG_FULLSCREEN
, falls angewendet) gelöscht, sodass die Systemleisten sichtbar bleiben. Wenn Sie möchten, dass die Systemleisten nach einigen Momenten wieder ausgeblendet werden, können Sie stattdessen das Flag SYSTEM_UI_FLAG_IMMERSIVE_STICKY
verwenden.
Transparente Systemleisten
Mit den neuen Designs Theme.Holo.NoActionBar.TranslucentDecor
und Theme.Holo.Light.NoActionBar.TranslucentDecor
können Sie die Systemleisten jetzt teilweise durchsichtig machen. Wenn Sie durchsichtige 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 fügen Sie die Stileigenschaften windowTranslucentNavigation
und windowTranslucentStatus
in Ihr Design ein.
Erweiterter Benachrichtigungs-Listener
Mit Android 4.3 wurden die NotificationListenerService
APIs hinzugefügt, mit denen Apps Informationen zu neuen Benachrichtigungen erhalten können, sobald sie vom System gepostet werden. Unter 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 ein Bundle
, um dem Benachrichtigungs-Builder zusätzliche Metadaten wie EXTRA_TITLE
und EXTRA_PICTURE
zu senden.
Die neue Notification.Action
-Klasse definiert die Eigenschaften einer Aktion, die an die Benachrichtigung angehängt ist. Sie können sie aus dem neuen Feld actions
abrufen.
Spiegelung von Zeichnungen für RTL-Layouts
Wenn Ihre App in älteren Android-Versionen Bilder enthält, deren horizontale Ausrichtung für Layouts von rechts nach links umgekehrt werden soll, müssen Sie das gespiegelte Bild in einem drawables-ldrtl/
-Ressourcenverzeichnis angeben. Jetzt kann das System Bilder automatisch für Sie spiegeln, indem Sie das Attribut autoMirrored
für eine Zeichnen-Ressource aktivieren oder setAutoMirrored()
aufrufen. Wenn diese Option aktiviert ist, wird der Drawable
automatisch gespiegelt, wenn die Layoutrichtung von rechts nach links ist.
Bedienungshilfen
Mit der Klasse View
können Sie jetzt „Live-Regionen“ für Bereiche Ihrer Benutzeroberfläche deklarieren, die dynamisch mit neuem Textinhalt aktualisiert werden. Fügen Sie dazu einfach das neue Attribut accessibilityLiveRegion
in Ihr XML-Layout ein oder rufen Sie setAccessibilityLiveRegion()
auf. Ein Anmeldebildschirm mit einem Textfeld, in dem die Meldung „Falsches Passwort“ angezeigt wird, sollte beispielsweise als Liveregion gekennzeichnet werden, damit der Screenreader die Meldung vorliest, wenn sie sich ändert.
Apps, die einen Bedienungshilfendienst bereitstellen, können ihre Funktionen jetzt auch mit neuen APIs erweitern, die Informationen zu Ansichtssammlungen wie Listen- oder Rasteransichten mithilfe von AccessibilityNodeInfo.CollectionInfo
und AccessibilityNodeInfo.CollectionItemInfo
liefern.
App-Berechtigungen
Die folgenden neuen Berechtigungen müssen von Ihrer App mit dem <uses-permission>
-Tag angefordert werden, um bestimmte neue APIs zu verwenden:
INSTALL_SHORTCUT
- Ermöglicht einer App, eine Verknüpfung im Launcher zu installieren
UNINSTALL_SHORTCUT
- Ermöglicht es einer App, eine Verknüpfung im Launcher zu deinstallieren
TRANSMIT_IR
- Ermöglicht einer Anwendung, den Infrarotsender des Geräts zu verwenden, sofern verfügbar
Hinweis:Ab Android 4.4 muss Ihre App auf der Plattform nicht mehr die WRITE_EXTERNAL_STORAGE
oder READ_EXTERNAL_STORAGE
abrufen, wenn Sie mithilfe von Methoden wie getExternalFilesDir()
auf Ihre app-spezifischen Bereiche des externen Speichers zugreifen möchten. Die Berechtigungen sind jedoch weiterhin erforderlich, wenn Sie auf die freigegebenen Bereiche des externen Speichers zugreifen möchten, die von getExternalStoragePublicDirectory()
bereitgestellt werden.
Gerätefunktionen
Im Folgenden finden Sie neue Gerätefunktionen, die Sie mit dem <uses-feature>
-Tag deklarieren können, um Ihre App-Anforderungen anzugeben und die Filterung bei Google Play zu aktivieren oder 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 über 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 Hardware-Schrittzähler.
FEATURE_SENSOR_STEP_DETECTOR
- Das Gerät enthält einen Hardware-Schrittzähler.
Eine detaillierte Übersicht über alle API-Änderungen in Android 4.4 finden Sie im API-Unterschiedsbericht.