Informationsarchitektur

Mit Android 8.0 wurde eine neue Informationsarchitektur für die Einstellungen eingeführt, um die Organisation der Einstellungen zu vereinfachen und Nutzern die Suche nach Einstellungen zum Anpassen ihrer Android-Geräte zu erleichtern. Mit Android 9 wurden einige Verbesserungen eingeführt, um mehr Einstellungsfunktionen 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 sind die 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 (eingeführt in Android 9): packages/apps/Settings/src/com/android/settings/core/BasePreferenceController.java

Implementierung

Gerätehersteller werden aufgefordert, die vorhandene Architektur für Einstellungen anzupassen und bei Bedarf zusätzliche Einstellungsseiten einzufügen, um partnerspezifische Funktionen zu berücksichtigen. Die Übertragung von Einstellungen von einer alten Seite (implementiert als SettingsPreferencePage) auf eine neue Seite (implementiert mit DashboardFragment) kann kompliziert sein. Die Einstellung auf der alten Seite wurde wahrscheinlich nicht mit einem PreferenceController implementiert.

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

Es wird dringend empfohlen, für jede 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 Stil von Plug-ins

Jedes Einstellungselement wird als Preference implementiert. Eine Einstellung kann ganz einfach von einer Seite auf eine andere verschoben werden.

Damit mehrere Einstellungen einfacher verschoben werden können, 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 daher aus einem einzelnen Host-Fragment und mehreren Einstellungscontrollern.

DashboardFragment

DashboardFragment ist der Host von Preference-Controllern im Plug-in-Stil. Das Fragment erbt von PreferenceFragment und enthält Hooks zum Erweitern und Aktualisieren von statischen und dynamischen Einstellungslisten.

Statische Einstellungen

Eine statische Liste mit Einstellungen 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 einem Intent dar, die zu einer externen oder internen Aktivität führt. Normalerweise führt der Intent zu einer anderen Einstellungsseite. Beispiel: Das Element „Google“ auf der Startseite der Einstellungen ist ein dynamisches Element. Dynamische Elemente werden in AndroidManifest (siehe unten) definiert und über einen FeatureProvider (definiert als DashboardFeatureProvider) geladen.

Dynamische Einstellungen sind aufwendiger als statisch konfigurierte Einstellungen. Entwickler sollten die Einstellung daher normalerweise statisch implementieren. Die dynamische Einstellung kann jedoch in folgenden Fällen nützlich sein:

  • Die Einstellung wird nicht direkt in der Einstellungen App implementiert, z. B. durch Einfügen einer Einstellung, die von OEM-/Mobilfunkanbieter-Apps implementiert wird.
  • 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 Einstellungen-App mit, zu welcher Kategorie sie gehört. Die Kategorie ist eine Konstante, die in CategoryKey definiert ist.
  • Optional: Fügen Sie einen Zusammenfassungstext hinzu, der angezeigt wird, wenn die Einstellung aufgerufen 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>

Zur Renderzeit 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 im Java-Code oder in XML definiert sind, verwaltet DashboardFragment die Logik für die Verarbeitung jeder Einstellung über PreferenceController (siehe unten). Sie werden dann in der Benutzeroberfläche als gemischte Liste angezeigt.

PreferenceController

Die Implementierung von PreferenceController in Android 9 und Android 8.x unterscheidet sich, wie in diesem Abschnitt beschrieben.

PreferenceController in Android 9-Release

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

Die Schnittstelle von PreferenceController ist als BasePreferenceController definiert. Sehen Sie sich beispielsweise 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 entsprechen, der von der Einstellungs-App standardmäßig unterstützt wird. TogglePreferenceController hat beispielsweise eine API, die direkt der Interaktion des Nutzers mit einer auf Ein/Aus-Schaltern basierenden Benutzeroberfläche für Einstellungen entspricht.

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 für das Fragment bietet das Dashboard eine Methode zum Anhängen eines PreferenceController vor der Anzeigezeit. Bei der Installation 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. Am onCreate() des Fragments werden alle Controller für die getAvailabilityStatus()-Methode aufgerufen. Wenn sie „true“ 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-Versionen

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

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

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

DashboardFragment zeigt eine Liste von PreferenceControllers auf dem Bildschirm an. Im 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

Eine Einstellung von Seite A auf Seite B verschieben

Wenn die Einstellung statisch in der XML-Datei der ursprünglichen Seite aufgeführt ist, folgen Sie der unten beschriebenen statischen Vorgehensweise für Ihre Android-Version. Andernfalls folgen Sie der dynamischen Vorgehensweise für die Verschiebung für Ihre Android-Version.

Statische Bewegung in Android 9

  1. Suchen Sie die XML-Dateien für die Einstellungen der ursprünglichen Seite und der Zielseite. Diese Informationen finden Sie in der getPreferenceScreenResId()-Methode der Seite.
  2. Entfernen Sie die Einstellung aus dem XML-Code der ursprünglichen Seite.
  3. Fügen Sie die Einstellung in die XML-Datei der Zielseite ein.
  4. Entfernen Sie die PreferenceController für diese Einstellung aus der Java-Implementierung der Originalseite. Normalerweise ist sie in createPreferenceControllers(). Der Controller wird möglicherweise direkt in XML deklariert.

    Hinweis: Die Einstellung hat möglicherweise keine PreferenceController.

  5. Instanziieren Sie PreferenceController im createPreferenceControllers() der Zielseite. Wenn PreferenceController in der XML-Datei der alten Seite definiert ist, müssen Sie es auch in der XML-Datei der neuen Seite definieren.

Dynamisches Verschieben in Android 9

  1. Ermitteln Sie, in welcher Kategorie sich die ursprüngliche und die Zielseite befinden. Diese Informationen finden Sie unter 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 repräsentiert.
  3. Legen Sie den Metadatenwert der Aktivität für com.android.settings.category auf den Kategorienschlüssel der neuen Seite fest.

Statische Bewegung in Android 8.x-Versionen

  1. Suchen Sie die XML-Dateien für die Einstellungen der ursprünglichen Seite und der Zielseite.
  2. Diese Informationen finden Sie in der getPreferenceScreenResId() -Methode der Seite.
  3. Entfernen Sie die Einstellung aus dem XML-Code der Originalseite.
  4. Fügen Sie die Einstellung in die XML-Datei der Zielseite ein.
  5. Entfernen Sie das PreferenceController für diese Einstellung in der Java-Implementierung der Originalseite. Normalerweise befindet sie sich in getPreferenceControllers().
  6. Hinweis:Es ist möglich, dass die Einstellung keine PreferenceController hat.

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

Dynamisches Verschieben in Android 8.x-Versionen

  1. Ermitteln Sie, in welcher Kategorie sich die ursprüngliche und die Zielseite befinden. Diese Informationen finden Sie unter 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 repräsentiert.
  3. Ändern Sie den Metadatenwert der Aktivität für com.android.settings.category und legen Sie den Wertpunkt auf den Kategorienschlüssel der neuen Seite fest.

Neue Einstellung auf einer Seite erstellen

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

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 der XML-Datei ein neues Preference-Element hinzu. Achten Sie darauf, dass sie eine eindeutige android:key hat.
  3. Definieren Sie eine PreferenceController für diese Einstellung in der getPreferenceControllers()-Methode der Seite.
    • In Android 8.x und optional in Android 9 instanziieren Sie ein PreferenceController für diese Einstellung in der createPreferenceControllers()-Methode der Seite.

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

    • Ab Android 9 können Sie die 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.ResetPreferenceController"/>

Dynamische Einstellung erstellen

  1. Ermitteln Sie, in welcher Kategorie sich die ursprüngliche und die Zielseite befinden. Diese Informationen finden Sie 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 abgeleitet wird.
  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 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 die Seite, die geändert wird, manuell. Die Seite sollte sofort aktualisiert werden.