Informationsarchitektur

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 CategoryKey definiert 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

  1. 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.
  2. Entfernen Sie die Einstellung aus dem XML der ursprünglichen Seite.
  3. Fügen Sie die Einstellung dem XML der Zielseite hinzu.
  4. Entfernen Sie den PreferenceController für diese Einstellung aus der Java-Implementierung der ursprünglichen Seite. Normalerweise befindet er sich in createPreferenceControllers(). Der Controller kann direkt in XML deklariert werden.

    Hinweis: Die Einstellung hat möglicherweise keinen PreferenceController.

  5. Instanziieren Sie den PreferenceController in der ZielseitecreatePreferenceControllers(). Wenn der PreferenceController in XML auf der alten Seite definiert ist, definieren Sie ihn auch in XML für die neue Seite.

Dynamische Verschiebung in Android 9

  1. Suchen Sie die Kategorie, die auf der ursprünglichen Seite und der Zielseite gehostet wird. Sie finden diese Informationen in DashboardFragmentRegistry.
  2. Ö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.
  3. Legen Sie den Metadatenwert der Aktivität für com.android.settings.category auf den Kategorieschlüssel der neuen Seite fest.

Statische Verschiebung in Android 8.x

  1. Suchen Sie die XML-Dateien für die Einstellungen der ursprünglichen Seite und der Zielseite.
  2. Sie finden diese Informationen in der Methode getPreferenceScreenResId() der Seite.
  3. Entfernen Sie die Einstellung aus dem XML der ursprünglichen Seite.
  4. Fügen Sie die Einstellung dem XML der Zielseite hinzu.
  5. Entfernen Sie den PreferenceController für diese Einstellung aus der Java-Implementierung der ursprünglichen Seite. Normalerweise befindet er sich in getPreferenceControllers().
  6. Hinweis:Die Einstellung hat möglicherweise keinen PreferenceController.

  7. Instanziieren Sie den PreferenceController in der ZielseitegetPreferenceControllers().

Dynamische Verschiebung in Android 8.x

  1. Suchen Sie die Kategorie, die auf der ursprünglichen Seite und der Zielseite gehostet wird. Sie finden diese Informationen in DashboardFragmentRegistry.
  2. Ö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.
  3. Ändern Sie den Metadatenwert der Aktivität für com.android.settings.category und 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

  1. Suchen Sie die XML-Dateien für die Einstellungen der Seite. Sie finden diese Informationen in der Methode getPreferenceScreenResId() der Seite.
  2. Fügen Sie in XML ein neues Einstellungselement hinzu. Achten Sie darauf, dass es einen eindeutigen android:key hat.
  3. Definieren Sie einen PreferenceController für diese Einstellung in der Methode getPreferenceControllers() der Seite.
    • In Android 8.x und optional in Android 9, instanziieren Sie einen PreferenceController für diese Einstellung in der Methode createPreferenceControllers() der Seite.

      Wenn diese Einstellung bereits an anderen Stellen vorhanden war, gibt es möglicherweise bereits einen PreferenceController dafür. Sie können den PreferenceController wiederverwenden, ohne einen neuen zu erstellen.

    • Ab Android 9 können Sie den PreferenceController in 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"/

Dynamische Einstellung erstellen

  1. Suchen Sie die Kategorie, die auf der ursprünglichen Seite und der Zielseite gehostet wird. Sie finden diese Informationen in DashboardFragmentRegistry.
  2. Erstellen Sie eine neue Aktivität in AndroidManifest.
  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 abgeleitet wird.
  2. 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.

  3. 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.