Informationsarchitektur

Mit Android 8.0 wurde eine neue Informationsarchitektur für die Einstellungen-App eingeführt, um die Organisation der Einstellungen zu vereinfachen und Nutzern die schnelle Suche nach Einstellungen zur Anpassung ihrer Android-Geräte zu erleichtern. Mit Android 9 wurden einige Verbesserungen eingeführt, um mehr Funktionen in den 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 dafür ist DisplaySettings: packages/apps/Settings/src/com/android/settings/DisplaySettings.java

Dateipfade für wichtige Komponenten sind unten 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 (in Android 9 eingeführt): packages/apps/Settings/src/com/android/settings/core/BasePreferenceController.java

Implementierung

Gerätehersteller werden aufgefordert, die vorhandene Architektur der Einstellungen anzupassen und nach Bedarf zusätzliche Seiten mit Einstellungen einzufügen, um partnerspezifische Funktionen zu berücksichtigen. Das Verschieben von Einstellungen von einer Legacy-Seite (implementiert als SettingsPreferencePage) auf eine neue Seite (mit DashboardFragment implementiert) kann kompliziert sein. Die Einstellung auf der alten Seite ist wahrscheinlich nicht mit einem PreferenceController implementiert.

Wenn Sie also die Einstellungen von einer alten Seite auf eine neue Seite verschieben, müssen Sie einen PreferenceController erstellen und den Code in den Controller verschieben, bevor Sie ihn in der neuen DashboardFragment instanziieren. Die für PreferenceController erforderlichen APIs sind in ihrem Namen beschrieben und im Javadoc dokumentiert.

Es wird dringend empfohlen, für jede PreferenceController einen Einheitentest hinzuzufügen. Wenn die Änderung bei AOSP eingereicht wird, ist ein Unittest erforderlich. Weitere Informationen zum Schreiben von Robolectric-basierten Tests finden Sie in der packages/apps/Settings/tests/robotests/README.md.

Informationsarchitektur im Plug-in-Stil

Jedes Element der Einstellungen wird als Einstellung implementiert. Eine Einstellung kann ganz einfach von einer Seite auf eine andere verschoben werden.

Damit sich mehrere Einstellungen leichter verschieben lassen, wurde in Android 8.0 ein Host-Fragment im Plug-in-Stil eingeführt, das Einstellungen enthält. Einstellungen werden als Plug-in-Controller modelliert. Daher besteht eine Seite mit Einstellungen aus einem einzelnen Hostfragment und mehreren Einstellungscontrollern.

DashboardFragment

DashboardFragment ist der Host für Plug-in-basierte Einstellungscontroller. Das Fragment wird von PreferenceFragment übernommen und enthält Hooks, mit denen sowohl statische als auch dynamische Einstellungslisten erweitert und aktualisiert werden können.

Statische Einstellungen

Eine statische Präferenzliste wird in XML mit dem Tag <Preference> definiert. Bei einer DashboardFragment-Implementierung wird mit der Methode getPreferenceScreenResId() definiert, welche XML-Datei die statische Liste der anzuzeigenden Einstellungen enthält.

Dynamische Einstellungen

Ein dynamisches Element stellt eine Kachel mit Intent dar, die zu einer externen oder internen Aktivität führt. Normalerweise führt der Intent zu einer anderen Einstellungsseite. Das Einstellungselement „Google“ auf der Startseite „Einstellungen“ ist beispielsweise ein dynamisches Element. Dynamische Elemente werden in AndroidManifest (siehe unten) definiert und über ein FeatureProvider (definiert als DashboardFeatureProvider) geladen.

Dynamische Einstellungen sind leistungsintensiver 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 App „Einstellungen“ implementiert, z. B. durch das Einfügen einer Einstellung, die von OEM-/Mobilfunkanbieter-Apps implementiert wurde.
  • Die Einstellung sollte 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 App „Einstellungen“ mit, zu welcher Kategorie sie gehört. Die Kategorie ist eine Konstante, die in CategoryKey definiert ist.
  • Optional: Fügen Sie eine Zusammenfassung hinzu, wenn die Einstellung angezeigt wird.

Hier ein Beispiel aus der Einstellungen App für DisplaySettings.

<activity android:name="Settings$DisplaySettingsActivity"
                   android:label="@string/display_settings"
                   android:icon="@drawable/ic_settings_display">
             <!-- Mark the activity as a dynamic setting -->
              <intent-filter>
                     <action android:name="com.android.settings.action.IA_SETTINGS" />
              </intent-filter>
             <!-- Tell Settings app which category it belongs to -->
              <meta-data android:name="com.android.settings.category"
                     android:value="com.android.settings.category.ia.homepage" />
             <!-- Add a summary text when the setting is displayed -->
              <meta-data android:name="com.android.settings.summary"
                     android:resource="@string/display_dashboard_summary"/>
             </activity>

Beim Rendern wird vom Fragment eine Liste der Einstellungen aus der statischen XML-Datei und den in AndroidManifest definierten dynamischen Einstellungen angefordert. Unabhängig davon, ob die PreferenceControllers in Java-Code oder in XML definiert sind, verwaltet DashboardFragment die Verarbeitungslogik jeder Einstellung über PreferenceController (siehe unten). Sie werden dann in der Benutzeroberfläche als gemischte Liste angezeigt.

PreferenceController

Zwischen der Implementierung von PreferenceController in Android 9 und Android 8.x gibt es Unterschiede, die in diesem Abschnitt beschrieben werden.

PreferenceController in der Android 9-Version

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. Sehen Sie sich zum Beispiel den Code in packages/apps/Settings/src/com/android/settings/core/ BasePreferenceController.java an.

Es gibt mehrere Unterklassen von BasePreferenceController, die jeweils einem bestimmten UI-Stil zugeordnet sind, der standardmäßig von der Einstellungen App unterstützt wird. TogglePreferenceController hat beispielsweise eine API, die direkt darauf abbildet, wie der Nutzer mit einer UI für die Einstellungsschalter interagieren soll.

BasePreferenceController enthält APIs wie getAvailabilityStatus(), displayPreference(), handlePreferenceTreeClicked(), usw. Eine ausführliche Dokumentation für jede API finden Sie in der Schnittstellenklasse.

Bei der Implementierung von BasePreferenceController (und deren Unterklassen wie TogglePreferenceController) ist zu beachten, dass die Signatur des Konstruktors einer der folgenden Optionen entsprechen muss:

  • public MyController(Context context, String key) {}
  • public MyController(Context context) {}

Beim Installieren einer Einstellung für das Fragment bietet das Dashboard eine Methode, um vor der Auslieferung ein PreferenceController anzuhängen. Bei der Installation wird der Controller mit dem Fragment verbunden, damit alle zukünftigen relevanten Ereignisse an den Controller gesendet werden.

DashboardFragment behält eine Liste von PreferenceControllers auf dem Bildschirm bei. Bei onCreate() des Fragments werden alle Controller für die Methode getAvailabilityStatus() aufgerufen. Wenn diese Methode „wahr“ zurückgibt, wird displayPreference() aufgerufen, um die Anzeigelogik zu verarbeiten. getAvailabilityStatus() ist auch wichtig, um dem Einstellungs-Framework mitzuteilen, welche Elemente bei der Suche verfügbar sind.

PreferenceController in Android 8.x-Releases

Ein PreferenceController enthält die gesamte Logik für die Interaktion mit der Einstellung, einschließlich Anzeige, Aktualisierung, Suchindexierung usw.

Entsprechend den Interaktionen mit den Einstellungen hat die Benutzeroberfläche von PreferenceController die APIs isAvailable(), displayPreference(), handlePreferenceTreeClicked() usw. Eine detaillierte Dokumentation zu jeder API finden Sie in der Benutzeroberflächenklasse.

Während der Installation einer Einstellung für das Fragment bietet das Dashboard eine Methode zum Anhängen einer PreferenceController vor der Anzeigezeit. Bei der Installation ist der Controller mit dem Fragment verbunden, sodass alle zukünftigen relevanten Ereignisse an den Controller gesendet werden.

DashboardFragment behält eine Liste von PreferenceControllers auf dem Bildschirm. Beim onCreate() des Fragments werden alle Controller für die isAvailable()-Methode aufgerufen. Wenn diese Methode „wahr“ zurückgibt, wird displayPreference() aufgerufen, um die Anzeigelogik zu verarbeiten.

DashboardFragment verwenden

Eine Einstellung von Seite A auf Seite B verschieben

Wenn die Einstellung in der XML-Datei der ursprünglichen Seite statisch aufgeführt ist, folgen Sie unten der Anleitung für die statische Umstellung für Ihre Android-Version. Folgen Sie andernfalls dem dynamischen Verschiebungsvorgang für Ihren Android-Release.

Statische Bewegung in Android 9

  1. Suchen Sie die bevorzugten XML-Dateien für die Originalseite und die Zielseite. Diese Informationen finden Sie in der getPreferenceScreenResId()-Methode der Seite.
  2. Entfernen Sie die Einstellung aus der XML-Datei der ursprünglichen Seite.
  3. Fügen Sie die Einstellung der XML-Datei der Zielseite hinzu.
  4. Entfernen Sie PreferenceController für diese Einstellung aus der Java-Implementierung der Originalseite. Normalerweise ist das createPreferenceControllers(). Der Controller kann auch direkt in XML deklariert werden.

    Hinweis: Die Einstellung hat möglicherweise keine PreferenceController.

  5. Instanziere die PreferenceController im createPreferenceControllers() der Zielseite. Wenn PreferenceController in der alten Seite in XML definiert ist, definieren Sie es auch in XML für die neue Seite.

Dynamisches Verschieben unter Android 9

  1. Finden Sie heraus, zu welcher Kategorie die Original- und Zielseite gehören. Diese Informationen finden Sie in DashboardFragmentRegistry.
  2. Öffnen Sie die Datei AndroidManifest.xml mit der Einstellung, die Sie verschieben möchten, und suchen Sie den Aktivitätseintrag, der diese Einstellung darstellt.
  3. Legen Sie den Metadatenwert der Aktivität für com.android.settings.category auf den Kategorieschlüssel der neuen Seite fest.

Statischer Umzug in Android 8.x-Releases

  1. Suchen Sie die XML-Dateien mit den Einstellungen für die ursprüngliche Seite und die Zielseite.
  2. Diese Informationen finden Sie in der getPreferenceScreenResId() -Methode der Seite.
  3. Entfernen Sie die Einstellung in der XML-Datei der Originalseite.
  4. Fügen Sie die Einstellung in die XML-Datei der Zielseite ein.
  5. Entfernen Sie PreferenceController für diese Einstellung in der Java-Implementierung der Originalseite. Normalerweise ist das getPreferenceControllers().
  6. Hinweis:Möglicherweise hat die Einstellung keine PreferenceController.

  7. Erstellen Sie eine Instanz von PreferenceController im getPreferenceControllers() der Zielseite.

Dynamische Verschiebung in Android 8.x-Releases

  1. Finden Sie heraus, zu welcher Kategorie die ursprüngliche und die Zielseite gehören. Sie finden diese Informationen unter DashboardFragmentRegistry.
  2. Öffnen Sie die Datei AndroidManifest.xml mit der Einstellung, die Sie verschieben möchten, und suchen Sie den Eintrag „Aktivität“ für diese Einstellung.
  3. Ändern Sie den Metadatenwert der Aktivität für com.android.settings.category und legen Sie den Wertpunkt auf den Kategorieschlüssel der neuen Seite fest.

Neue Einstellung auf einer Seite erstellen

Wenn die Einstellung in der XML-Datei der ursprünglichen Seite statisch aufgeführt ist, folgen Sie der Anleitung unten unter statisch. Andernfalls folgen Sie dem dynamischen Verfahren.

Statische Einstellung erstellen

  1. Suchen Sie die XML-Dateien mit den Einstellungen für die Seite. Sie finden diese Informationen in der Methode „getPreferenceScreenResId()“ der Seite.
  2. Fügen Sie der XML-Datei ein neues Element „Preference“ hinzu. Die Fahrtbeschreibung muss eine eindeutige android:key haben.
  3. Definiere in der getPreferenceControllers()-Methode der Seite eine PreferenceController für diese Einstellung.
    • Unter Android 8.x und optional unter Android 9 müssen Sie in der createPreferenceControllers()-Methode der Seite eine PreferenceController für diese Einstellung instanziieren.

      Wenn diese Einstellung bereits an anderer Stelle vorhanden war, gibt es möglicherweise bereits eine PreferenceController dafür. Sie können die PreferenceController wiederverwenden, ohne eine neue zu erstellen.

    • Ab Android 9 können Sie PreferenceController neben der Einstellung in XML deklarieren. Beispiel:
      <Preference
              android:key="reset_dashboard"
              android:title="@string/reset_dashboard_title"
              settings:controller="com.android.settings.system.ResetPreferenceController"/>

Dynamische Einstellungen erstellen

  1. Finden Sie heraus, zu welcher Kategorie die ursprüngliche und die Zielseite gehören. Sie finden diese Informationen unter DashboardFragmentRegistry.
  2. Neue Aktivität in AndroidManifest erstellen
  3. 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.category auf denselben Wert fest, der in Schritt 1 definiert wurde.

Neue Seite erstellen

  1. Erstellen Sie ein neues Fragment, das von DashboardFragment erbt.
  2. Definieren Sie die Kategorie in DashboardFragmentRegistry.

    Hinweis:Dieser Schritt ist optional. Wenn Sie auf dieser Seite keine dynamischen Einstellungen benötigen, müssen Sie keinen Kategorieschlüssel angeben.

  3. Folgen Sie der Anleitung, um die für diese Seite erforderlichen Einstellungen hinzuzufügen. Weitere Informationen finden Sie im Abschnitt Implementierung.

Zertifizierungsstufe

  • Führe die robolectric-Tests in den Einstellungen aus. Alle vorhandenen und neuen Tests sollten funktionieren.
  • Erstellen und installieren Sie die Einstellungen und öffnen Sie dann die zu ändernde Seite manuell. Die Seite sollte sofort aktualisiert werden.