Informationsarchitektur

Mit Android 8.0 wurde eine neue Informationsarchitektur für die App „Einstellungen“ eingeführt, die die Organisation von Einstellungen vereinfacht und es Nutzern erleichtert, Einstellungen zum Anpassen ihrer Android-Geräte schnell zu finden. Mit Android 9 wurden einige Verbesserungen eingeführt, um mehr Einstellungen und eine einfachere Implementierung zu bieten.

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

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
  • Abstrakte Präferenzen-Controller: 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äteherstellern wird empfohlen, die vorhandene Architektur mit Einstellungsinformationen anzupassen und bei Bedarf zusätzliche Einstellungsseiten einzufügen, um partnerspezifische Funktionen zu berücksichtigen. Das Verschieben von Einstellungen von einer Legacy-Seite (implementiert als SettingsPreferencePage) auf eine neue Seite, die mit DashboardFragment implementiert wurde, kann kompliziert sein. Die Einstellung von der Legacy-Seite wurde wahrscheinlich nicht mit einer PreferenceController implementiert.

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

Es wird dringend empfohlen, für jede PreferenceController einen Unittest 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 Readme-Datei packages/apps/Settings/tests/robotests/README.md.

Informationsarchitektur im Plug-in-Stil

Jedes Einstellungselement wird als Einstellung implementiert. Präferenzen lassen sich ganz einfach von einer Seite auf eine andere verschieben.

Um das Verschieben mehrerer Einstellungen zu erleichtern, wurde mit Android 8.0 ein Hostfragment im Plug-in-Stil eingeführt, das Einstellungselemente enthält. Einstellungselemente werden als Controller im Plug-in-Stil modelliert. Daher besteht eine Einstellungsseite aus einem einzelnen Hostfragment und mehreren Einstellungs-Controllern.

Dashboard-Fragment

DashboardFragment ist der Host von bevorzugten Controllern im Plug-in-Stil. Das Fragment übernimmt die Einstellungen von PreferenceFragment und verfügt über Hooks zum Erweitern und Aktualisieren von statischen und dynamischen Einstellungslisten.

Statische Einstellungen

Eine statische Einstellungsliste 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 definiert (wie unten erläutert) und über ein FeatureProvider (definiert als DashboardFeatureProvider) geladen.

Dynamische Einstellungen sind komplexer als statisch konfigurierte Einstellungen. Daher sollten Entwickler die Einstellung in der Regel als statische Einstellungen implementieren. Die dynamische Einstellung kann jedoch nützlich sein, wenn eine der folgenden Bedingungen zutrifft:

  • Die Einstellung ist nicht direkt in der App „Einstellungen“ implementiert. Beispielsweise wird eine von OEM-/Mobilfunkanbieter-Apps implementierte Einstellung eingefügt.
  • 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 und wird in CategoryKey definiert.
  • Optional: Fügen Sie eine Zusammenfassung hinzu, wenn die Einstellung angezeigt wird.

Hier ist ein Beispiel aus den Einstellungen 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 fordert das Fragment eine Liste von Einstellungen sowohl aus dem statischen XML als auch den dynamischen Einstellungen an, die in AndroidManifest definiert sind. Unabhängig davon, ob die PreferenceControllers in Java-Code oder in XML definiert sind, verwaltet DashboardFragment die Verarbeitungslogik jeder Einstellung über PreferenceController (siehe unten). Dann werden sie in der UI als gemischte Liste angezeigt.

Präferenz-Controller

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

PreferenceController in 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 abgeleitete Klassen von BasePreferenceController, die jeweils einem bestimmten UI-Stil zugeordnet sind, der von der App „Einstellungen“ standardmäßig unterstützt wird. TogglePreferenceController hat beispielsweise eine API, die direkt der Interaktion des Nutzers mit einer Ein/Aus-Schaltfläche für Einstellungen zugeordnet ist.

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

Eine Einschränkung für die Implementierung von BasePreferenceController (und dessen abgeleiteten Klassen wie TogglePreferenceController) besteht darin, dass die Konstruktorsignatur einer der folgenden Optionen entsprechen muss:

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

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 bei. Im onCreate() des Fragments werden alle Controller für die Methode getAvailabilityStatus() aufgerufen. Wenn sie "true" zurückgibt, wird displayPreference() zur Verarbeitung der Anzeigelogik aufgerufen. getAvailabilityStatus() ist auch wichtig, um dem Einstellungen-Framework mitzuteilen, welche Elemente während 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 Präferenzinteraktionen verfügt die Schnittstelle von PreferenceController über die APIs isAvailable(), displayPreference(), handlePreferenceTreeClicked() usw. Eine detaillierte Dokumentation zu den einzelnen APIs finden Sie in der Schnittstellenklasse.

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 Methode isAvailable() aufgerufen. Wenn sie "true" zurückgibt, wird displayPreference() zur Verarbeitung der Anzeigelogik aufgerufen.

DashboardFragment verwenden

Eine Einstellung von Seite A nach B verschieben

Wenn die Einstellung statisch in der bevorzugten XML-Datei der Originalseite aufgeführt ist, folgen Sie der statischen Verschiebung für Ihren Android-Release unten. Folgen Sie andernfalls dem dynamischen Verschiebungsvorgang für Ihren Android-Release.

Statischer Umzug in Android 9

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

    Hinweis: Die Einstellung hat möglicherweise keinen PreferenceController-Wert.

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

Dynamische Veränderungen in Android 9

  1. Ermitteln Sie, welche Kategorie die Originalseite und die Zielseite hosten. 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. 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 bevorzugten XML-Dateien für die Originalseite und die Zielseite.
  2. Sie finden diese Informationen in der getPreferenceScreenResId() -Methode der Seite.
  3. Entfernen Sie die Einstellung in der XML-Datei der Originalseite.
  4. Fügen Sie die Einstellung der XML-Datei der Zielseite hinzu.
  5. Entfernen Sie PreferenceController für diese Einstellung in der Java-Implementierung der Originalseite. Normalerweise befindet sie sich in getPreferenceControllers().
  6. Hinweis:Möglicherweise hat die Einstellung keine PreferenceController.

  7. Instanziieren Sie PreferenceController im getPreferenceControllers() der Zielseite.

Dynamische Verschiebung in Android 8.x-Releases

  1. Ermitteln Sie, welche Kategorie die Originalseite und die Zielseite hosten. Die entsprechenden Informationen finden Sie 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 statisch in der bevorzugten XML-Datei der Originalseite aufgeführt ist, folge der statischen Vorgehensweise unten. Folgen Sie andernfalls dem dynamischen Verfahren.

Statische Einstellung erstellen

  1. Suche nach den bevorzugten XML-Dateien für die Seite. Sie finden diese Informationen in der Methode getPreferenceScreenResId() der Seite.
  2. Fügen Sie ein neues Einstellungselement in der XML-Datei hinzu. Er muss eine eindeutige android:key haben.
  3. Definiere in der getPreferenceControllers()-Methode der Seite eine PreferenceController für diese Einstellung.
    • In Android 8.x und optional in Android 9 muss ein PreferenceController für diese Einstellung in der createPreferenceControllers()-Methode der Seite instanziiert werden.

      Wenn diese Einstellung bereits an anderen Stellen existiert, ist möglicherweise bereits ein PreferenceController dafür vorhanden. Sie können die PreferenceController wiederverwenden, ohne ein neues erstellen zu müssen.

    • 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. Ermitteln Sie, welche Kategorie die Originalseite und die Zielseite hosten. Die entsprechenden Informationen finden Sie unter DashboardFragmentRegistry.
  2. Neue Aktivität in AndroidManifest erstellen
  3. Füge der neuen Activity-Klasse 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. Erstellt ein neues Fragment, das die Übernahme von DashboardFragment übernimmt.
  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. Führen Sie die Schritte zum Hinzufügen der Einstellungen aus, die für diese Seite erforderlich sind. Weitere Informationen finden Sie im Abschnitt Implementierung.

Zertifizierungsstufe

  • Führe 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 die Seite, die geändert wird, manuell. Die Seite sollte sofort aktualisiert werden.