Kochbuch für große Bildschirme

Android bietet alle Voraussetzungen für Fünf-Sterne-Apps auf großen Bildschirmen. In den Rezepten dieses Kochbuchs werden ausgewählte Zutaten zur Lösung bestimmter Entwicklungsprobleme ausgewählt und kombiniert. Jedes Rezept enthält Best Practices, hochwertige Codebeispiele und Schritt-für-Schritt-Anleitungen, die dir dabei helfen, ein Spitzenkoch mit einem großen Bildschirm zu werden.

Bewertungen

Die Rezepte werden danach bewertet, wie gut sie den Qualitätsrichtlinien für Apps mit großen Bildschirmen entsprechen.

Bewertung mit fünf Sternen Erfüllt die Kriterien für Tier 1, große Bildschirme differenziert
Bewertung mit vier Sternen Erfüllt die Kriterien für Tier 2, für große Bildschirme optimiert
Bewertung mit 3 Sternen Erfüllt die Kriterien für Tier 3, „Großer Bildschirm“ geeignet
Bewertung mit zwei Sternen Bietet einige Funktionen für große Bildschirme, entspricht aber nicht den Qualitätsrichtlinien für große Displays
Bewertung mit einem Stern Erfüllt die Anforderungen eines bestimmten Anwendungsfalls, unterstützt aber große Bildschirme nicht richtig

Support für Chromebook-Kameras

Bewertung mit 3 Sternen

Mach bei Google Play von Chromebook-Nutzern auf sich aufmerksam.

Falls Ihre Kamera-App nur mit grundlegenden Kamerafunktionen kompatibel ist, sollten Sie nicht zulassen, dass App-Shops Nutzer von Chromebooks daran hindern, sie zu installieren, nur weil Sie versehentlich erweiterte Kamerafunktionen von High-End-Smartphones angegeben haben.

Chromebooks haben eine integrierte Frontkamera, die für den Nutzer sichtbar ist und sich gut für Videokonferenzen, Schnappschüsse und andere Anwendungen eignet. Allerdings haben nicht alle Chromebooks eine Rückkamera (zur Welt gerichtet) und die meisten Kameras für Nutzer auf Chromebooks unterstützen weder Autofokus noch Blitz.

Best Practices

Vielseitige Kamera-Apps unterstützen alle Geräte unabhängig von der Kamerakonfiguration: Geräte mit Frontkameras, Rückkameras und über USB verbundene externe Kameras.

Damit Ihre App von App-Shops für möglichst viele Geräte verwendet werden kann, müssen Sie immer alle von Ihrer App verwendeten Kamerafunktionen deklarieren und explizit angeben, ob die Funktionen erforderlich sind.

Zutaten

  • Berechtigung CAMERA: Gewährt Ihrer App Zugriff auf die Kameras eines Geräts
  • <uses-feature>-Manifestelement: Informiert App-Shops über die von deiner App verwendeten Funktionen
  • Attribut required: Gibt App-Shops an, ob deine App ohne eine bestimmte Funktion funktioniert

Schritte

Zusammenfassung

Deklarieren Sie die Berechtigung CAMERA. Kamerafunktionen deklarieren, die eine grundlegende Kameraunterstützung bieten. Geben Sie an, ob die einzelnen Funktionen erforderlich sind.

1. Berechtigung „CAMERA“ deklarieren

Füge dem App-Manifest die folgende Berechtigung hinzu:

<uses-permission android:name="android.permission.CAMERA" />
2. Grundlegende Kamerafunktionen deklarieren

Fügen Sie dem App-Manifest die folgenden Funktionen hinzu:

<uses-feature android:name="android.hardware.camera.any" android:required="false" />
<uses-feature android:name="android.hardware.camera" android:required="false" />
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />
<uses-feature android:name="android.hardware.camera.flash" android:required="false" />
3. Angeben, ob die einzelnen Funktionen erforderlich sind

Lege android:required="false" für die Funktion „android.hardware.camera.any“ fest, um den Zugriff auf deine App für Geräte zu aktivieren, die eine integrierte oder externe Kamera oder gar keine Kamera haben.

Legen Sie für die anderen Funktionen android:required="false" fest, damit Geräte wie Chromebooks ohne Rückkamera, Autofokus oder Blitz auf Ihre App in App-Shops zugreifen können.

Ergebnis

Chromebook-Nutzer können Ihre App aus Google Play und anderen App-Shops herunterladen und installieren. Und bei Geräten mit voll funktionsfähiger Kameraunterstützung wie Smartphones sind die Kamerafunktionen nicht eingeschränkt.

Indem Sie die von Ihrer App unterstützten Kamerafunktionen und die für Ihre App erforderlichen Funktionen explizit festlegen, haben Sie Ihre App für so viele Geräte wie möglich verfügbar gemacht.

Weitere Informationen

Weitere Informationen finden Sie unter Kamerahardwarefunktionen in der Dokumentation zu <uses-feature>.

App-Ausrichtung auf Smartphones, aber nicht auf Geräten mit großem Bildschirm eingeschränkt

Bewertung mit zwei Sternen

Ihre App funktioniert hervorragend auf Smartphones im Hochformat. Sie haben daher die App auf das Hochformat beschränkt. Aber Sie sehen die Chance, auf großen Bildschirmen im Querformat mehr zu machen.

Wie kann das in beiden Fällen funktionieren? Du solltest die App auf das Hochformat auf kleinen Bildschirmen beschränken und auf großen Bildschirmen Querformat aktivieren?

Best Practices

Die besten Apps berücksichtigen Nutzereinstellungen wie die Geräteausrichtung.

In den Qualitätsrichtlinien für Apps für große Bildschirme wird empfohlen, dass Apps alle Gerätekonfigurationen unterstützen, einschließlich Hoch- und Querformat, Mehrfenstermodus sowie zugeklappt und aufgeklappt auf faltbaren Geräten. Apps sollten Layouts und Benutzeroberflächen für verschiedene Konfigurationen optimieren und den Status bei Konfigurationsänderungen speichern und wiederherstellen.

Dieses Rezept ist eine vorübergehende Maßnahme – eine Prise großen Bildschirm unterstützt. Verwenden Sie das Rezept, bis Sie Ihre App verbessern können, um alle Gerätekonfigurationen vollständig zu unterstützen.

Zutaten

  • screenOrientation: Einstellung des App-Manifests, mit der Sie angeben können, wie Ihre App auf Änderungen der Geräteausrichtung reagieren soll
  • Jetpack WindowManager: Bibliotheken, mit denen Größe und Seitenverhältnis des App-Fensters bestimmt werden können; abwärtskompatibel mit API-Level 14
  • Activity#setRequestedOrientation(): Methode, mit der Sie die Ausrichtung der App zur Laufzeit ändern können

Schritte

Zusammenfassung

Sie können festlegen, dass die App Ausrichtungsänderungen im App-Manifest standardmäßig verarbeitet. Ermitteln Sie zur Laufzeit die Größe des App-Fensters. Wenn das App-Fenster klein ist, können Sie die Ausrichtung der App einschränken, indem Sie die Einstellung für die Ausrichtung des Manifests überschreiben.

1. Ausrichtungseinstellung im App-Manifest festlegen

Du kannst es entweder vermeiden, das screenOrientation-Element des App-Manifests zu deklarieren (in diesem Fall wird standardmäßig unspecified verwendet) oder die Bildschirmausrichtung auf fullUser festlegen. Wenn der Nutzer die sensorbasierte Drehung nicht gesperrt hat, unterstützt deine App alle Geräteausrichtungen.

<activity
    android:name=".MyActivity"
    android:screenOrientation="fullUser">

Der Unterschied zwischen unspecified und fullUser ist subtil, aber wichtig. Wenn Sie keinen screenOrientation-Wert angeben, wählt das System die Ausrichtung aus. Die Richtlinie, mit der das System die Ausrichtung definiert, kann sich dann von Gerät zu Gerät unterscheiden. Andererseits entspricht die Angabe von fullUser eher dem Verhalten, das der Nutzer für das Gerät definiert hat: Wenn der Nutzer die sensorbasierte Drehung gesperrt hat, folgt die App der Nutzerpräferenz. Andernfalls lässt das System jede der vier möglichen Bildschirmausrichtungen zu (Hochformat, Querformat, Umgekehrtes Hochformat oder umgekehrtes Querformat). Weitere Informationen finden Sie unter android:screenOrientation.

2. Bildschirmgröße bestimmen

Wenn das Manifest alle vom Nutzer erlaubten Ausrichtungen unterstützt, können Sie die App-Ausrichtung programmatisch basierend auf der Bildschirmgröße angeben.

Fügen Sie der Datei build.gradle oder build.gradle.kts des Moduls die Jetpack WindowManager-Bibliotheken hinzu:

Kotlin

implementation("androidx.window:window:version")
implementation("androidx.window:window-core:version")

Groovig

implementation 'androidx.window:window:version'
implementation 'androidx.window:window-core:version'

Verwenden Sie die Methode WindowMetricsCalculator#computeMaximumWindowMetrics() Jetpack WindowManager, um die Bildschirmgröße des Geräts als WindowMetrics-Objekt abzurufen. Die Fenstermesswerte können mit Fenstergrößenklassen verglichen werden, um zu entscheiden, wann die Ausrichtung eingeschränkt werden soll.

Windows-Größenklassen stellen die Haltepunkte zwischen kleinen und großen Bildschirmen bereit.

Verwenden Sie die Haltepunkte WindowWidthSizeClass#COMPACT und WindowHeightSizeClass#COMPACT, um die Bildschirmgröße zu bestimmen:

Kotlin

/** Determines whether the device has a compact screen. **/
fun compactScreen() : Boolean {
    val metrics = WindowMetricsCalculator.getOrCreate().computeMaximumWindowMetrics(this)
    val width = metrics.bounds.width()
    val height = metrics.bounds.height()
    val density = resources.displayMetrics.density
    val windowSizeClass = WindowSizeClass.compute(width/density, height/density)

    return windowSizeClass.windowWidthSizeClass == WindowWidthSizeClass.COMPACT ||
        windowSizeClass.windowHeightSizeClass == WindowHeightSizeClass.COMPACT
}

Java

/** Determines whether the device has a compact screen. **/
private boolean compactScreen() {
    WindowMetrics metrics = WindowMetricsCalculator.getOrCreate().computeMaximumWindowMetrics(this);
    int width = metrics.getBounds().width();
    int height = metrics.getBounds().height();
    float density = getResources().getDisplayMetrics().density;
    WindowSizeClass windowSizeClass = WindowSizeClass.compute(width/density, height/density);
    return windowSizeClass.getWindowWidthSizeClass() == WindowWidthSizeClass.COMPACT ||
                windowSizeClass.getWindowHeightSizeClass() == WindowHeightSizeClass.COMPACT;
}
    Hinweis:
  • Die obigen Beispiele werden als Methoden einer Aktivität implementiert. Daher wird die Aktivität als this im Argument von computeMaximumWindowMetrics() dereferenziert.
  • Die Methode computeMaximumWindowMetrics() wird anstelle von computeCurrentWindowMetrics() verwendet, weil die App im Mehrfenstermodus gestartet werden kann, in dem die Einstellung für die Bildschirmausrichtung ignoriert wird. Es macht keinen Sinn, die Größe des App-Fensters zu bestimmen und die Ausrichtungseinstellung zu überschreiben, es sei denn, das App-Fenster nimmt den gesamten Bildschirm des Geräts ein.

Eine Anleitung zum Deklarieren von Abhängigkeiten, um die Methode computeMaximumWindowMetrics() in Ihrer App verfügbar zu machen, finden Sie unter WindowManager.

3. Einstellung für App-Manifest überschreiben

Wenn du festgestellt hast, dass das Gerät eine kompakte Bildschirmgröße hat, kannst du Activity#setRequestedOrientation() aufrufen, um die Einstellung screenOrientation des Manifests zu überschreiben:

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    requestedOrientation = if (compactScreen())
        ActivityInfo.SCREEN_ORIENTATION_PORTRAIT else
        ActivityInfo.SCREEN_ORIENTATION_FULL_USER
    ...
    // Replace with a known container that you can safely add a
    // view to where the view won't affect the layout and the view
    // won't be replaced.
    val container: ViewGroup = binding.container

    // Add a utility view to the container to hook into
    // View.onConfigurationChanged. This is required for all
    // activities, even those that don't handle configuration
    // changes. You can't use Activity.onConfigurationChanged,
    // since there are situations where that won't be called when
    // the configuration changes. View.onConfigurationChanged is
    // called in those scenarios.
    container.addView(object : View(this) {
        override fun onConfigurationChanged(newConfig: Configuration?) {
            super.onConfigurationChanged(newConfig)
            requestedOrientation = if (compactScreen())
                ActivityInfo.SCREEN_ORIENTATION_PORTRAIT else
                ActivityInfo.SCREEN_ORIENTATION_FULL_USER
        }
    })
}

Java

@Override
protected void onCreate(Bundle savedInstance) {
    super.onCreate(savedInstanceState);
    if (compactScreen()) {
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
    } else {
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_USER);
    }
    ...
    // Replace with a known container that you can safely add a
    // view to where the view won't affect the layout and the view
    // won't be replaced.
    ViewGroup container = binding.container;

    // Add a utility view to the container to hook into
    // View.onConfigurationChanged. This is required for all
    // activities, even those that don't handle configuration
    // changes. You can't use Activity.onConfigurationChanged,
    // since there are situations where that won't be called when
    // the configuration changes. View.onConfigurationChanged is
    // called in those scenarios.
    container.addView(new View(this) {
        @Override
        protected void onConfigurationChanged(Configuration newConfig) {
            super.onConfigurationChanged(newConfig);
            if (compactScreen()) {
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
            } else {
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_USER);
            }
        }
    });
}

Wenn Sie die Logik in die Methoden onCreate() und View.onConfigurationChanged() aufnehmen, können Sie die maximalen Fenstermesswerte abrufen und die Ausrichtungseinstellung überschreiben, wenn die Größe der Aktivität geändert oder zwischen den Displays gewechselt wird, z. B. nach der Drehung eines Geräts oder wenn ein faltbares Gerät zugeklappt oder aufgeklappt wird. Weitere Informationen dazu, wann Konfigurationsänderungen vorgenommen werden und wann sie zu einer Neuerstellung von Aktivitäten führen, findest du unter Konfigurationsänderungen verarbeiten.

Ergebnis

Ihre App sollte jetzt auf kleinen Displays im Hochformat gehalten werden, unabhängig davon, ob das Gerät gedreht wird. Auf großen Bildschirmen sollte die App Quer- und Hochformat unterstützen.

Weitere Informationen

Hilfe bei der Aktualisierung Ihrer App, damit alle Gerätekonfigurationen dauerhaft unterstützt werden, finden Sie hier:

Medienwiedergabe mit externer Tastatur Leertaste pausieren und fortsetzen

Bewertung mit vier Sternen

Bei der Optimierung für den großen Bildschirm können Sie auch externe Tastatureingaben verarbeiten, z. B. auf das Drücken der Leertaste reagieren, um die Wiedergabe von Videos und anderen Medien zu pausieren oder fortzusetzen. Dies ist besonders nützlich für Tablets, die oft mit externen Tastaturen verbunden werden, und Chromebooks, die normalerweise mit externen Tastaturen ausgestattet sind, aber im Tablet-Modus verwendet werden können.

Wenn Medien das einzige Element des Fensters sind (z. B. die Videowiedergabe im Vollbildmodus), reagieren Sie auf Tastendruckereignisse auf Aktivitätsebene oder in Jetpack Compose auf Bildschirmebene.

Best Practices

Bei jeder Mediendatei in Ihrer App sollten Nutzer die Möglichkeit haben, die Wiedergabe zu pausieren und fortzusetzen, indem sie auf einer physischen Tastatur die Leertaste drücken.

Zutaten

Compose

  • onPreviewKeyEvent: Modifier, die es einer Komponente ermöglicht, Hardwareschlüsselereignisse abzufangen, wenn sie (oder eines ihrer untergeordneten Elemente) fokussiert ist.
  • onKeyEvent: Ähnlich wie onPreviewKeyEvent ermöglicht dieses Modifier-Objekt, dass eine Komponente Hardware-Schlüsselereignisse abfangen kann, wenn sie (oder eines ihrer untergeordneten Elemente) im Fokus ist.

Aufrufe

  • onKeyUp(): Wird aufgerufen, wenn ein Schlüssel freigegeben und von einer Ansicht in einer Aktivität nicht verarbeitet wird.

Schritte

Zusammenfassung

Ansichtsbasierte Apps und Apps, die auf Jetpack Compose basieren, reagieren auf Tastendruck auf ähnliche Weise: Die App muss auf Tastendruckereignisse warten, die Ereignisse filtern und auf ausgewählte Tastenbetätigungen reagieren, z. B. beim Drücken der Leertaste.

1. Auf Tastaturereignisse warten

Aufrufe

Überschreiben Sie in einer Aktivität in Ihrer App die Methode onKeyUp():

Kotlin

override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean {
    ...
}

Java

@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
    ...
}

Die Methode wird jedes Mal aufgerufen, wenn eine gedrückte Taste freigegeben wird. Sie wird also genau einmal für jeden Tastenanschlag ausgelöst.

Compose

Mit Jetpack Compose können Sie entweder den onPreviewKeyEvent- oder den onKeyEvent-Modifikator auf dem Bildschirm verwenden, über den der Tastenanschlag verwaltet wird:

Column(modifier = Modifier.onPreviewKeyEvent { event ->
    if (event.type == KeyEventType.KeyUp) {
        ...
    }
    ...
})

oder

Column(modifier = Modifier.onKeyEvent { event ->
    if (event.type == KeyEventType.KeyUp) {
        ...
    }
    ...
})

2. Filter Leertaste drücken

Filtern Sie innerhalb der Methode onKeyUp() oder der Modifikatormethoden onPreviewKeyEvent und onKeyEvent nach KeyEvent.KEYCODE_SPACE, um das richtige Ereignis an Ihre Medienkomponente zu senden:

Aufrufe

Kotlin

if (keyCode == KeyEvent.KEYCODE_SPACE) {
    togglePlayback()
    return true
}
return false

Java

if (keyCode == KeyEvent.KEYCODE_SPACE) {
    togglePlayback();
    return true;
}
return false;

Compose

Column(modifier = Modifier.onPreviewKeyEvent { event ->
    if (event.type == KeyEventType.KeyUp && event.key == Key.Spacebar) {
        ...
    }
    ...
})

oder

Column(modifier = Modifier.onKeyEvent { event ->
    if (event.type == KeyEventType.KeyUp && event.key == Key.Spacebar) {
        ...
    }
    ...
})

Ergebnis

Deine App kann jetzt auf das Drücken der Leertaste reagieren, um ein Video oder andere Medien zu pausieren und fortzusetzen.

Weitere Informationen

Weitere Informationen zu Tastaturereignissen und ihrer Verwaltung finden Sie unter Tastatureingabe.

Handflächenablehnung mit Eingabestift

Bewertung mit fünf Sternen

Ein Eingabestift kann auf großen Bildschirmen ein außerordentlich produktives und kreatives Werkzeug sein. Wenn Nutzende jedoch mit einem Eingabestift zeichnen, schreiben oder mit einer App interagieren, berühren sie manchmal den Bildschirm mit der Handfläche. Das Touch-Ereignis kann deiner App gemeldet werden, bevor das System das Ereignis als versehentliche Berührung der Handfläche erkennt und ablehnt.

Best Practices

Ihre App muss irrelevante Touch-Ereignisse erkennen und ignorieren. Android bricht einen Handkontakt ab, indem ein MotionEvent-Objekt gesendet wird. Suchen Sie das Objekt auf ACTION_CANCEL oder ACTION_POINTER_UP und FLAG_CANCELED, um festzustellen, ob die durch die Berührung der Handfläche verursachte Geste abgelehnt werden soll.

Zutaten

  • MotionEvent: Steht für Berührungs- und Bewegungsereignisse. Enthält die Informationen, die erforderlich sind, um zu bestimmen, ob ein Ereignis ignoriert werden soll.
  • OnTouchListener#onTouch(): Empfängt MotionEvent Objekte.
  • MotionEvent#getActionMasked(): gibt die mit einem Bewegungsereignis verknüpfte Aktion zurück.
  • ACTION_CANCEL: MotionEvent-Konstante, die angibt, dass eine Geste rückgängig gemacht werden soll.
  • ACTION_POINTER_UP: MotionEvent-Konstante, die angibt, dass ein anderer Punkt als der erste Zeiger nach oben gestiegen ist, d. h. den Kontakt mit dem Gerätebildschirm aufgegeben hat.
  • FLAG_CANCELED: MotionEvent-Konstante, die angibt, dass der nach oben gerichtete Zeiger ein unbeabsichtigtes Berührungsereignis verursacht. Zu ACTION_POINTER_UP- und ACTION_CANCEL-Ereignissen unter Android 13 (API-Level 33) und höher hinzugefügt.

Schritte

Zusammenfassung

Untersuchen Sie MotionEvent-Objekte, die an Ihre App gesendet wurden. Verwenden Sie die MotionEvent APIs, um Ereigniseigenschaften festzulegen:

  • Einzelpunktereignisse: Suchen Sie nach ACTION_CANCEL. Suche unter Android 13 und höher auch nach FLAG_CANCELED.
  • Multi-Pointer-Ereignisse: Suchen Sie unter Android 13 und höher nach ACTION_POINTER_UP und FLAG_CANCELED.

Auf ACTION_CANCEL und ACTION_POINTER_UP/FLAG_CANCELED Termine antworten.

1. Bewegungsereignisobjekte erfassen

Füge deiner App ein OnTouchListener hinzu:

Kotlin

val myView = findViewById<View>(R.id.myView).apply {
    setOnTouchListener { view, event ->
        // Process motion event.
    }
}

Java

View myView = findViewById(R.id.myView);
myView.setOnTouchListener( (view, event) -> {
    // Process motion event.
});
2. Ereignisaktion und -flags festlegen

Suchen Sie nach ACTION_CANCEL. Dieser Wert gibt ein Single-Pointer-Ereignis auf allen API-Ebenen an. Unter Android 13 und höher: ACTION_POINTER_UP auf FLAG_CANCELED. prüfen

Kotlin

val myView = findViewById<View>(R.id.myView).apply {
    setOnTouchListener { view, event ->
        when (event.actionMasked) {
            MotionEvent.ACTION_CANCEL -> {
                //Process canceled single-pointer motion event for all SDK versions.
            }
            MotionEvent.ACTION_POINTER_UP -> {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU &&
                   (event.flags and MotionEvent.FLAG_CANCELED) == MotionEvent.FLAG_CANCELED) {
                    //Process canceled multi-pointer motion event for Android 13 and higher.
                }
            }
        }
        true
    }
}

Java

View myView = findViewById(R.id.myView);
myView.setOnTouchListener( (view, event) -> {
    switch (event.getActionMasked()) {
        case MotionEvent.ACTION_CANCEL:
            // Process canceled single-pointer motion event for all SDK versions.
        case MotionEvent.ACTION_UP:
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU &&
               (event.getFlags() & MotionEvent.FLAG_CANCELED) == MotionEvent.FLAG_CANCELED) {
                //Process canceled multi-pointer motion event for Android 13 and higher.
            }
    }
    return true;
});
3. Geste rückgängig machen

Nachdem Sie die Berührung der Handfläche identifiziert haben, können Sie die Bildschirmeffekte der Touch-Geste rückgängig machen.

In Ihrer App muss ein Verlauf der Nutzeraktionen gespeichert werden, damit unbeabsichtigte Eingaben wie das Berühren der Handfläche rückgängig gemacht werden können. Ein Beispiel finden Sie im Codelab Unterstützung des Eingabestifts in einer Android-App verbessern unter Einfache Zeichen-App implementieren.

Ergebnis

Deine App kann jetzt Palm Touch-Ereignisse für Multi-Pointer-Ereignisse auf Android 13- und höher-API-Levels sowie für Einzel-Zeiger-Ereignisse auf allen API-Levels identifizieren und ablehnen.

Weitere Informationen

Weitere Informationen finden Sie hier:

WebView-Statusverwaltung

Bewertung mit 3 Sternen

WebView ist eine häufig verwendete Komponente, die ein erweitertes System für die Statusverwaltung bietet. Ein WebView muss bei Konfigurationsänderungen ihren Status und die Scrollposition beibehalten. Ein WebView kann die Scrollposition verlieren, wenn der Nutzer das Gerät dreht oder ein faltbares Smartphone aufklappt. In diesem Fall muss der Nutzer noch einmal vom oberen Rand des WebView zur vorherigen Scrollposition scrollen.

Best Practices

Minimieren Sie die Häufigkeit, mit der WebView neu erstellt wird. WebView ist gut darin, seinen Status zu verwalten. Sie können diese Qualität nutzen, indem Sie so viele Konfigurationsänderungen wie möglich verwalten. Deine App muss Konfigurationsänderungen verarbeiten, da die Activity-Neuerstellung (die Art der Verarbeitung von Konfigurationsänderungen durch das System) auch die WebView neu erstellt. Dadurch verliert das WebView seinen Status.

Zutaten

  • android:configChanges: Attribut des <activity>-Manifestelements. Listet die Konfigurationsänderungen auf, die von der Aktivität verarbeitet werden.
  • View#invalidate(): Methode, die dazu führt, dass eine Ansicht neu gezeichnet wird. Übernommen von WebView.

Schritte

Zusammenfassung

Wenn du den Status WebView speichern möchtest, solltest du so weit wie möglich die Neuerstellung von Activity vermeiden und das WebView dann entwerten, damit seine Größe unter Beibehaltung des Zustands geändert werden kann.

1. Konfigurationsänderungen zur AndroidManifest.xml-Datei Ihrer Anwendung hinzufügen

Sie können die Neuerstellung von Aktivitäten vermeiden, indem Sie die Konfigurationsänderungen angeben, die von Ihrer App und nicht vom System vorgenommen werden:

<activity
  android:name=".MyActivity"
  android:configChanges="screenLayout|orientation|screenSize
      |keyboard|keyboardHidden|smallestScreenSize" />

2. WebView entwerten, wenn deine App eine Konfigurationsänderung erhält

Kotlin

override fun onConfigurationChanged(newConfig: Configuration) {
    super.onConfigurationChanged(newConfig)
    webView.invalidate()
}

Java

@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    webview.invalidate();
}

Dieser Schritt gilt nur für das Ansichtssystem, da Jetpack Compose nichts entwerten muss, um die Größe der Composable-Elemente richtig anzupassen. Allerdings wird ein WebView von Compose häufig neu erstellt, wenn es nicht korrekt verwaltet wird. Mit dem Accompanist WebView-Wrapper können Sie den WebView-Status in Ihren Compose-Apps speichern und wiederherstellen.

Ergebnis

Die WebView-Komponenten deiner App behalten jetzt ihren Status und die Scroll-Position bei mehreren Konfigurationsänderungen, von der Größenänderung über die Ausrichtungsänderung bis hin zum Falten und Aufklappen.

Weitere Informationen

Weitere Informationen zu Konfigurationsänderungen und deren Verwaltung finden Sie unter Konfigurationsänderungen verarbeiten.

RecyclerView-Statusverwaltung

Bewertung mit 3 Sternen

Mit RecyclerView lassen sich große Datenmengen mit minimalen grafischen Ressourcen darstellen. Während RecyclerView durch die Liste der Elemente scrollt, verwendet RecyclerView die View-Instanzen von Elementen, die außerhalb des Bildschirms gescrollt wurden, um neue Elemente zu erstellen, während sie auf dem Bildschirm scrollen. Konfigurationsänderungen, z. B. die Drehung des Geräts, können jedoch den Status eines RecyclerView zurücksetzen, sodass Nutzer noch einmal an ihre vorherige Position in der Liste der RecyclerView-Elemente scrollen müssen.

Best Practices

RecyclerView sollte bei allen Konfigurationsänderungen seinen Status, insbesondere die Scrollposition, und den Status seiner Listenelemente beibehalten.

Zutaten

Schritte

Zusammenfassung

Legen Sie die Richtlinie zur Wiederherstellung des Zustands von RecyclerView.Adapter fest, um die Scrollposition RecyclerView zu speichern. Speichern Sie den Status von RecyclerView Listeneinträgen. Fügen Sie den Status der Listenelemente dem RecyclerView-Adapter hinzu und stellen Sie den Status der Listenelemente wieder her, wenn sie an eine ViewHolder gebunden sind.

1. Wiederherstellungsrichtlinie für Adapter aktivieren

Aktivieren Sie die Richtlinie zur Zustandswiederherstellung des RecyclerView-Adapters, damit die Scrollposition des RecyclerView über Konfigurationsänderungen hinweg beibehalten wird. Fügen Sie dem Adapterkonstruktor die Richtlinienspezifikation hinzu:

Kotlin

class MyAdapter() : RecyclerView.Adapter() {
    init {
        stateRestorationPolicy = StateRestorationPolicy.PREVENT_WHEN_EMPTY
    }
    ...
}

Java

class MyAdapter extends RecyclerView.Adapter {

    public Adapter() {
        setStateRestorationPolicy(StateRestorationPolicy.PREVENT_WHEN_EMPTY);
    }
    ...
}

2. Status von zustandsorientierten Listenelementen speichern

Speichert den Status komplexer RecyclerView-Listenelemente, z. B. Elemente, die EditText-Elemente enthalten. Um beispielsweise den Status eines EditText zu speichern, fügen Sie einen Callback hinzu, der einem onClick-Handler ähnelt, um Textänderungen zu erfassen. Legen Sie im Callback fest, welche Daten gespeichert werden sollen:

Kotlin

input.addTextChangedListener(
    afterTextChanged = { text ->
        text?.let {
            // Save state here.
        }
    }
)

Java

input.addTextChangedListener(new TextWatcher() {
    
    ...

    @Override
    public void afterTextChanged(Editable s) {
        // Save state here.
    }
});

Deklariere den Callback in deinem Activity oder Fragment. Verwenden Sie ViewModel, um den Status zu speichern.

3. Status des Listeneintrags zu Adapter hinzufügen

Fügen Sie den Status von Listeneinträgen zu Ihrem RecyclerView.Adapter hinzu. Übergeben Sie den Elementstatus an den Adapterkonstruktor, wenn der Host Activity oder Fragment erstellt wird:

Kotlin

val adapter = MyAdapter(items, viewModel.retrieveState())

Java

MyAdapter adapter = new MyAdapter(items, viewModel.retrieveState());

4. Status der Liste im ViewHolder des Adapters wiederherstellen

Wenn Sie in der RecyclerView.Adapter ein ViewHolder an ein Element binden, stellen Sie den Status des Elements wieder her:

Kotlin

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
    ...
    val item = items[position]
    val state = states.firstOrNull { it.item == item }

    if (state != null) {
        holder.restore(state)
    }
}

Java

@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
    ...
    Item item = items[position];
    Arrays.stream(states).filter(state -> state.item == item)
        .findFirst()
        .ifPresent(state -> holder.restore(state));
}

Ergebnis

RecyclerView kann jetzt die Scrollposition und alle Elemente in der RecyclerView-Liste wiederherstellen.

Weitere Informationen

Verwaltung abnehmbarer Tastatur

Bewertung mit 3 Sternen

Die Unterstützung für abnehmbare Tastaturen trägt dazu bei, die Produktivität der Nutzer auf Geräten mit großen Bildschirmen zu maximieren. Android löst jedes Mal eine Konfigurationsänderung aus, wenn eine Tastatur an ein Gerät angehängt oder von diesem getrennt wird. Dies kann zu einem Verlust des UI-Status führen. Ihre App kann entweder den Status speichern und wiederherstellen, sodass das System die Wiederherstellung von Aktivitäten übernehmen kann, oder die Neuerstellung von Aktivitäten bei Änderungen der Tastaturkonfiguration einschränken. In jedem Fall werden alle Daten im Zusammenhang mit der Tastatur in einem Configuration-Objekt gespeichert. Die Felder keyboard und keyboardHidden des Konfigurationsobjekts enthalten Informationen zum Tastaturtyp und zu dessen Verfügbarkeit.

Best Practices

Für große Bildschirme optimierte Apps unterstützen alle Arten von Eingabegeräten, von Software- und Hardwaretastaturen bis hin zu Eingabestiften, Maus, Touchpad und anderen Peripheriegeräten.

Die Unterstützung externer Tastaturen umfasst Konfigurationsänderungen, die Sie auf zwei Arten verwalten können:

  1. Lassen Sie das System die aktuell ausgeführte Aktivität neu erstellen. Sie verwalten den Status Ihrer App.
  2. Verwalten Sie die Konfigurationsänderung selbst (die Aktivität wird nicht neu erstellt):
    • Alle tastaturbezogenen Konfigurationswerte deklarieren
    • Handler für Konfigurationsänderungen erstellen

Produktivitätsanwendungen, die häufig eine detaillierte Steuerung der UI für die Texteingabe und andere Eingaben erfordern, können vom Do-it-yourself-Ansatz für die Verarbeitung von Konfigurationsänderungen profitieren.

In bestimmten Fällen kann es sinnvoll sein, das App-Layout zu ändern, wenn eine Hardwaretastatur angeschlossen oder getrennt wird, z. B. um mehr Platz für Tools oder Bearbeitungsfenster zu schaffen.

Da die einzige zuverlässige Möglichkeit zum Überwachen von Konfigurationsänderungen darin besteht, die onConfigurationChanged()-Methode einer Ansicht zu überschreiben, können Sie Ihrer App-Aktivität eine neue View-Instanz hinzufügen und im onConfigurationChanged()-Handler der Ansicht auf Konfigurationsänderungen reagieren, die durch das Verbinden oder Trennen der Tastatur verursacht wurden.

Zutaten

  • android:configChanges: Attribut des <activity>-Elements des App-Manifests. Informiert das System über Konfigurationsänderungen, die von der App verwaltet werden.
  • View#onConfigurationChanged(): Methode, die auf die Weitergabe einer neuen Anwendungskonfiguration reagiert.

Schritte

Zusammenfassung

Geben Sie das Attribut configChanges an und fügen Sie tastaturbezogene Werte hinzu. Fügen Sie der Ansichtshierarchie der Aktivität eine View hinzu und warten Sie auf Konfigurationsänderungen.

1. Attribut „configChanges“ deklarieren

Aktualisieren Sie das <activity>-Element im App-Manifest, indem Sie die keyboard|keyboardHidden-Werte zur Liste der bereits verwalteten Konfigurationsänderungen hinzufügen:

<activity
      …
      android:configChanges="...|keyboard|keyboardHidden">

2. Leere Ansicht zur Ansichtshierarchie hinzufügen

Geben Sie eine neue Ansicht an und fügen Sie den Handler-Code in die onConfigurationChanged()-Methode der Ansicht ein:

Kotlin

val v = object : View(this) {
  override fun onConfigurationChanged(newConfig: Configuration?) {
    super.onConfigurationChanged(newConfig)
    // Handler code here.
  }
}

Java

View v = new View(this) {
    @Override
    protected void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        // Handler code here.
    }
};

Ergebnis

Ihre App reagiert jetzt darauf, wenn eine externe Tastatur angeschlossen oder getrennt wird, ohne dass die aktuell ausgeführte Aktivität neu erstellt wird.

Weitere Informationen

Informationen zum Speichern des UI-Status Ihrer App bei Konfigurationsänderungen wie dem Anhängen oder Trennen der Tastatur finden Sie unter UI-Status speichern.