Mit Android 8.0 wurde eine neue Informationsarchitektur für die Einstellungen eingeführt, um die Organisation der Einstellungen zu vereinfachen und Nutzern das schnelle Auffinden von Einstellungen zum Anpassen ihrer Android-Geräte zu erleichtern. In Android 9 wurden einige Verbesserungen vorgenommen, um mehr Einstellungen und eine einfachere Implementierung zu ermöglichen.
Beispiele und Quelle
Die meisten Seiten in den Einstellungen werden derzeit mit dem neuen Framework implementiert. Ein gutes Beispiel ist DisplaySettings:
packages/apps/Settings/src/com/android/settings/DisplaySettings.java
Unten sind die Dateipfade für wichtige Komponenten aufgeführt:
- CategoryKey:
packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java - DashboardFragmentRegistry:
packages/apps/Settings/src/com/android/settings/dashboard/DashboardFragmentRegistry.java - DashboardFragment:
packages/apps/Settings/src/com/android/settings/dashboard/DashboardFragment.java - AbstractPreferenceController:
frameworks/base/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java - BasePreferenceController (eingeführt in Android 9):
packages/apps/Settings/src/com/android/settings/core/BasePreferenceController.java
Implementierung
Gerätehersteller sollten die vorhandene Informationsarchitektur der Einstellungen anpassen und bei Bedarf zusätzliche Einstellungsseiten einfügen, um partnerspezifische Funktionen zu berücksichtigen. Das Verschieben von Einstellungen von einer älteren Seite (implementiert als SettingsPreferencePage) auf eine neue Seite (implementiert mit DashboardFragment) kann kompliziert sein. Die Einstellung auf der älteren Seite wird wahrscheinlich nicht mit einem PreferenceController implementiert.
Wenn Sie also eine Einstellung von einer älteren Seite auf eine neue Seite verschieben, müssen Sie einen PreferenceController erstellen und den Code in den Controller verschieben, bevor Sie ihn im neuen DashboardFragment instanziieren. Die APIs, die PreferenceController benötigt, sind in ihrem Namen beschrieben und in Javadoc dokumentiert.
Es wird dringend empfohlen, für jeden PreferenceController einen Unittest hinzuzufügen.
Wenn die Änderung an AOSP gesendet wird, ist ein Unittest erforderlich.
Weitere Informationen zum Schreiben von Robolectric-basierten Tests finden Sie in der Readme-Datei packages/apps/Settings/tests/robotests/README.md.
Informationsarchitektur im Plug-in-Stil
Jedes Einstellungselement wird als Einstellung implementiert. Eine Einstellung kann einfach von einer Seite auf eine andere verschoben werden.
Um das Verschieben mehrerer Einstellungen zu erleichtern, wurde in Android 8.0 ein Host-Fragment im Plug-in-Stil eingeführt, das Einstellungselemente enthält. Einstellungselemente werden als Controller im Plug-in-Stil modelliert. Eine Einstellungsseite besteht also aus einem einzelnen Host-Fragment und mehreren Einstellungscontrollern.
DashboardFragment
DashboardFragment ist der Host von Einstellungscontrollern im Plug-in-Stil.
Das Fragment wird von PreferenceFragment abgeleitet und hat Hooks zum Erweitern und Aktualisieren sowohl statischer als auch dynamischer Einstellungslisten.
Statische Einstellungen
Eine statische Einstellungsliste wird in XML mit dem <Preference> Tag definiert. Eine DashboardFragment-Implementierung verwendet die Methode getPreferenceScreenResId(), um zu definieren, welche XML-Datei die statische Liste der anzuzeigenden Einstellungen enthält.
Dynamische Einstellungen
Ein dynamisches Element stellt eine Kachel mit einer Absicht dar, die zu einer externen oder internen Aktivität führt. Normalerweise führt die Absicht zu einer anderen Einstellungsseite. Das Einstellungselement „Google“ auf der Startseite der Einstellungen ist beispielsweise ein dynamisches Element. Dynamische
Elemente werden in AndroidManifest (siehe unten) definiert und geladen
über einen FeatureProvider (definiert als
DashboardFeatureProvider).
Dynamische Einstellungen sind aufwendiger als statisch konfigurierte Einstellungen. Daher sollten Entwickler die Einstellung normalerweise als statische Einstellung implementieren. Die dynamische Einstellung kann jedoch in folgenden Fällen nützlich sein:
- Die Einstellung ist nicht direkt in der Einstellungen implementiert (z. B. das Einfügen einer Einstellung, die von OEM-/Mobilfunkanbieter-Apps implementiert wurde).
- Die Einstellung soll auf der Startseite der Einstellungen angezeigt werden.
- Sie haben bereits eine Aktivität für die Einstellung und möchten die zusätzliche statische Konfiguration nicht implementieren.
So konfigurieren Sie eine Aktivität als dynamische Einstellung:
- Markieren Sie die Aktivität als dynamische Einstellung, indem Sie der Aktivität einen Intent-Filter hinzufügen.
- Teilen Sie der Einstellungen mit, zu welcher Kategorie sie gehört. Die Kategorie ist eine Konstante, die in
CategoryKeydefiniert ist. - Optional: Fügen Sie einen Zusammenfassungstext hinzu, wenn die Einstellung angezeigt wird.
Hier ein Beispiel aus der Einstellungen für DisplaySettings.
<activity android:name="Settings$DisplaySettingsActivity" android:label="@string/display_settings" android:icon="@draw>able/ic_settin<gs_display" !-- Mark the ac>tivity as a dyn<amic setting >-- inten<t-filter action android:name="com.and>roid.settings.a<ction.IA_SETTI>NGS" / < /intent-filter !-- Tell Sett>ings app which <category it belongs to -- meta-data android:name="com.android.settings.category" android:v>alue="com<.android.settings.category.ia.homepage" / > !-- Add a <summary text when the setting is displayed -- meta-data android:name="com.android.settings.summary" > < androi>d:resource="@string/display_dashboard_summary"/ /activity
Zur Renderingzeit fordert das Fragment eine Liste von Einstellungen sowohl aus statischem XML als auch aus dynamischen Einstellungen an, die in AndroidManifest definiert sind. Unabhängig davon, ob die PreferenceController in Java-Code oder in XML definiert sind, verwaltet DashboardFragment die Verarbeitungslogik jeder Einstellung über PreferenceController (siehe unten). Anschließend werden sie in der Benutzeroberfläche als gemischte Liste angezeigt.
PreferenceController
Es gibt Unterschiede zwischen der Implementierung von PreferenceController in Android 9 und Android 8.x, wie in diesem Abschnitt beschrieben.
PreferenceController in Android 9
Ein PreferenceController enthält die gesamte Logik für die Interaktion mit der Einstellung, einschließlich Anzeige, Aktualisierung, Suchindexierung usw.
Die Schnittstelle von PreferenceController ist als
BasePreferenceController definiert. Ein Beispiel finden Sie im Code unter
packages/apps/Settings/src/com/android/settings/core/
BasePreferenceController.java
Es gibt mehrere Unterklassen von BasePreferenceController, die jeweils einem bestimmten UI-Stil zugeordnet sind, der von der Einstellungen standardmäßig unterstützt wird. TogglePreferenceController hat beispielsweise eine API, die direkt zuordnet, wie der Nutzer mit einer auf Umschaltern basierenden Einstellungs-UI interagieren sollte.
BasePreferenceController hat APIs wie
getAvailabilityStatus(), displayPreference(),
handlePreferenceTreeClicked(), usw. Eine detaillierte Dokumentation für jede
API finden Sie in der Schnittstellenklasse.
Eine Einschränkung bei der Implementierung von BasePreferenceController (und seinen Unterklassen wie TogglePreferenceController) besteht darin, dass die Konstruktorsignatur mit einer der folgenden übereinstimmen muss:
public MyController(Context context, String key) {}public MyController(Context context) {}
Beim Installieren einer Einstellung im Fragment bietet das Dashboard eine Methode zum Anhängen eines PreferenceController vor der Anzeigezeit. Zur Installationszeit wird der Controller mit dem Fragment verbunden, sodass alle zukünftigen relevanten Ereignisse an den Controller gesendet werden.
DashboardFragment enthält eine Liste von PreferenceController auf dem Bildschirm. Bei onCreate() des Fragments werden alle Controller für die Methode getAvailabilityStatus() aufgerufen. Wenn sie „true“ zurückgibt, wird displayPreference() aufgerufen, um die Anzeigelogik zu verarbeiten.
getAvailabilityStatus() ist auch wichtig, um dem Einstellungsframework mitzuteilen, welche Elemente bei der Suche verfügbar sind.
PreferenceController in Android 8.x
Ein PreferenceController enthält die gesamte Logik für die Interaktion mit der Einstellung, einschließlich Anzeige, Aktualisierung, Suchindexierung usw.
Entsprechend den Einstellungsinteraktionen hat die Schnittstelle von
PreferenceController APIs wie isAvailable(),
displayPreference(), handlePreferenceTreeClicked() usw.
Eine detaillierte Dokumentation zu jeder API finden Sie in der Schnittstellenklasse.
Beim Installieren einer Einstellung im Fragment bietet das Dashboard eine Methode zum Anhängen eines PreferenceController vor der Anzeigezeit. Zur Installationszeit wird der Controller mit dem Fragment verbunden, sodass alle zukünftigen relevanten Ereignisse an den Controller gesendet werden.
DashboardFragment enthält eine Liste von PreferenceControllers
auf dem Bildschirm. Bei onCreate() des Fragments werden alle Controller für die Methode isAvailable() aufgerufen. Wenn sie „true“ zurückgibt, wird displayPreference() aufgerufen, um die Anzeigelogik zu verarbeiten.
DashboardFragment verwenden
Einstellung von Seite A nach Seite B verschieben
Wenn die Einstellung statisch in der Einstellungs-XML-Datei der ursprünglichen Seite aufgeführt ist, folgen Sie der statischen Verschiebungsprozedur für Ihre Android-Version unten. Andernfalls folgen Sie der dynamischen Verschiebungsprozedur für Ihre Android-Version.
Statische Verschiebung in Android 9
- Suchen Sie die XML-Dateien für die Einstellungen der ursprünglichen Seite und der Zielseite. Sie finden diese Informationen in der Methode
getPreferenceScreenResId()der Seite. - Entfernen Sie die Einstellung aus dem XML der ursprünglichen Seite.
- Fügen Sie die Einstellung dem XML der Zielseite hinzu.
- Entfernen Sie den
PreferenceControllerfür diese Einstellung aus der Java-Implementierung der ursprünglichen Seite. Normalerweise befindet er sich increatePreferenceControllers(). Der Controller kann direkt in XML deklariert werden.Hinweis: Die Einstellung hat möglicherweise keinen
PreferenceController. - Instanziieren Sie den
PreferenceControllerin der ZielseitecreatePreferenceControllers(). Wenn derPreferenceControllerin XML auf der alten Seite definiert ist, definieren Sie ihn auch in XML für die neue Seite.
Dynamische Verschiebung in Android 9
- Suchen Sie die Kategorie, die auf der ursprünglichen Seite und der Zielseite gehostet wird. Sie finden diese Informationen in
DashboardFragmentRegistry. - Öffnen Sie die Datei
AndroidManifest.xml, die die Einstellung enthält, die Sie verschieben möchten, und suchen Sie den Aktivitätseintrag, der diese Einstellung darstellt. - Legen Sie den Metadatenwert der Aktivität für
com.android.settings.categoryauf den Kategorieschlüssel der neuen Seite fest.
Statische Verschiebung in Android 8.x
- Suchen Sie die XML-Dateien für die Einstellungen der ursprünglichen Seite und der Zielseite. Sie finden diese Informationen in der Methode
- Entfernen Sie die Einstellung aus dem XML der ursprünglichen Seite.
- Fügen Sie die Einstellung dem XML der Zielseite hinzu.
- Entfernen Sie den
PreferenceControllerfür diese Einstellung aus der Java-Implementierung der ursprünglichen Seite. Normalerweise befindet er sich ingetPreferenceControllers(). - Instanziieren Sie den
PreferenceControllerin der ZielseitegetPreferenceControllers().
getPreferenceScreenResId()
der Seite.
Hinweis:Die Einstellung hat möglicherweise keinen PreferenceController.
Dynamische Verschiebung in Android 8.x
- Suchen Sie die Kategorie, die auf der ursprünglichen Seite und der Zielseite gehostet wird. Sie finden diese Informationen in
DashboardFragmentRegistry. - Öffnen Sie die Datei
AndroidManifest.xml, die die Einstellung enthält, die Sie verschieben möchten, und suchen Sie den Aktivitätseintrag, der diese Einstellung darstellt. - Ändern Sie den Metadatenwert der Aktivität für
com.android.settings.categoryund legen Sie den Wert auf den Kategorieschlüssel der neuen Seite fest.
Neue Einstellung auf einer Seite erstellen
Wenn die Einstellung statisch in der Einstellungs-XML-Datei der ursprünglichen Seite aufgeführt ist, folgen Sie der statischen Prozedur unten. Andernfalls folgen Sie der dynamischen Prozedur.
Statische Einstellung erstellen
- Suchen Sie die XML-Dateien für die Einstellungen der Seite. Sie finden diese Informationen in der Methode getPreferenceScreenResId() der Seite.
- Fügen Sie in XML ein neues Einstellungselement hinzu. Achten Sie darauf, dass es einen eindeutigen
android:keyhat. -
Definieren Sie einen
PreferenceControllerfür diese Einstellung in der MethodegetPreferenceControllers()der Seite.- In Android 8.x und optional in Android 9,
instanziieren Sie einen
PreferenceControllerfür diese Einstellung in der MethodecreatePreferenceControllers()der Seite.Wenn diese Einstellung bereits an anderen Stellen vorhanden war, gibt es möglicherweise bereits einen
PreferenceControllerdafür. Sie können denPreferenceControllerwiederverwenden, ohne einen neuen zu erstellen. -
Ab Android 9 können Sie den
PreferenceControllerin XML neben der Einstellung deklarieren. Beispiel:<Preference android:key="reset_dashboard" android:title="@string/reset_dashboard_title" settings:controller="com.android.settings.system.Re>setPreferenceController"/
- In Android 8.x und optional in Android 9,
instanziieren Sie einen
Dynamische Einstellung erstellen
- Suchen Sie die Kategorie, die auf der ursprünglichen Seite und der Zielseite gehostet wird. Sie finden diese Informationen in
DashboardFragmentRegistry. - Erstellen Sie eine neue Aktivität in
AndroidManifest. - Fügen Sie der neuen Aktivität die erforderlichen Metadaten hinzu, um die Einstellung zu definieren. Legen Sie den Metadatenwert für
com.android.settings.categoryauf denselben Wert fest, der in Schritt 1 definiert wurde.
Neue Seite erstellen
- Erstellen Sie ein neues Fragment, das von
DashboardFragmentabgeleitet wird. - Definieren Sie die Kategorie in
DashboardFragmentRegistry.Hinweis:Dieser Schritt ist optional. Wenn Sie keine dynamischen Einstellungen auf dieser Seite benötigen, müssen Sie keinen Kategorieschlüssel angeben.
- Folgen Sie der Anleitung zum Hinzufügen der für diese Seite erforderlichen Einstellungen. Weitere Informationen finden Sie im Abschnitt Implementierung.
Zertifizierungsstufe
- Führen Sie die Robolectric-Tests in den Einstellungen aus. Alle vorhandenen und neuen Tests sollten bestanden werden.
- Erstellen und installieren Sie die Einstellungen und öffnen Sie dann manuell die Seite, die geändert wird. Die Seite sollte sofort aktualisiert werden.