Architektura informacji

W Androidzie 8.0 wprowadziliśmy nową architekturę informacji w aplikacji Ustawienia, aby uprościć sposób organizacji ustawień i ułatwić użytkownikom szybkie znajdowanie ustawień umożliwiających dostosowanie urządzeń z Androidem. Android 9 wprowadził pewne ulepszenia, które zapewniają więcej funkcji Ustawień i ułatwiają ich wdrażanie.

Przykłady i źródło

Większość stron w Ustawieniach jest obecnie zaimplementowana przy użyciu nowych ram. Dobrym przykładem jest DisplaySettings:packages/apps/Settings/src/com/android/settings/DisplaySettings.java

Ścieżki plików ważnych komponentów znajdziesz poniżej:

  • 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 (wprowadzony w Androidzie 9): packages/apps/Settings/src/com/android/settings/core/BasePreferenceController.java

Implementacja

Zachęcamy producentów urządzeń do dostosowania istniejącej architektury informacji w Ustawieniach i wstawiania dodatkowych stron ustawień w razie potrzeby, aby uwzględnić funkcje specyficzne dla partnera. Przenoszenie ustawień ze starszej strony (wdrożonej jako SettingsPreferencePage) na nową stronę (wdrożoną za pomocą DashboardFragment) może być skomplikowane. Ustawienie ze starszej strony prawdopodobnie nie jest zaimplementowane za pomocą PreferenceController.

Dlatego podczas przenoszenia ustawień ze starszej strony na nową musisz utworzyć PreferenceController i przenieść kod do kontrolera przed utworzeniem instancji w nowym DashboardFragment. Interfejsy API, których PreferenceControllerwymaga, są opisane w nazwie i udokumentowane w Javadoc.

Zdecydowanie zalecamy dodanie testu jednostkowego dla każdego PreferenceController. Jeśli zmiana zostanie przesłana do AOSP, wymagany jest test jednostkowy. Więcej informacji o pisaniu testów opartych na Robolectric znajdziesz w pliku README packages/apps/Settings/tests/robotests/README.md.

Architektura informacji w stylu wtyczek

Każdy element ustawień jest implementowany jako ustawienie. Ustawienie można łatwo przenieść z jednej strony na drugą.

Aby ułatwić przenoszenie wielu ustawień, w Androidzie 8.0 wprowadzono fragment hosta w stylu wtyczki, który zawiera elementy ustawień. Elementy ustawień są modelowane jako kontrolery w stylu wtyczek. Dlatego strona ustawień składa się z jednego fragmentu hosta i wielu kontrolerów ustawień.

DashboardFragment

DashboardFragment jest hostem kontrolerów ustawień w stylu wtyczek. Fragment dziedziczy po PreferenceFragment i ma punkty zaczepienia, które umożliwiają rozwijanie i aktualizowanie zarówno statycznych, jak i dynamicznych list preferencji.

Ustawienia statyczne

Statyczna lista preferencji jest zdefiniowana w formacie XML za pomocą tagu <Preference>. Implementacja A DashboardFragment korzysta z metody getPreferenceScreenResId(), aby określić, który plik XML zawiera statyczną listę preferencji do wyświetlenia.

Ustawienia dynamiczne

Element dynamiczny reprezentuje kartę z intencją, która prowadzi do zewnętrznego lub wewnętrznego działania. Zwykle intencja prowadzi do innej strony ustawień. Na przykład element „Google” na stronie głównej Ustawień jest elementem dynamicznym. Elementy dynamiczne są zdefiniowane w AndroidManifest (omówionej poniżej) i wczytywane za pomocą FeatureProvider (zdefiniowanej jako DashboardFeatureProvider).

Ustawienia dynamiczne są bardziej złożone niż ustawienia skonfigurowane statycznie, dlatego zwykle deweloperzy powinni implementować ustawienia statyczne. Ustawienie dynamiczne może być jednak przydatne w tych przypadkach:

  • Ustawienie nie jest bezpośrednio zaimplementowane w aplikacji Ustawienia (np. wstrzykiwanie ustawienia zaimplementowanego przez aplikacje OEM lub operatora).
  • Ustawienie powinno być widoczne na stronie głównej Ustawień.
  • Masz już aktywność związaną z tym ustawieniem i nie chcesz implementować dodatkowej konfiguracji statycznej.

Aby skonfigurować aktywność jako ustawienie dynamiczne:

  • Oznacz aktywność jako ustawienie dynamiczne, dodając do niej filtr intencji.
  • Wskaż w aplikacji Ustawienia, do której kategorii należy aplikacja. Kategoria jest stałą zdefiniowaną w CategoryKey.
  • Opcjonalnie: dodaj tekst podsumowania, który będzie wyświetlany, gdy ustawienie jest widoczne.

Oto przykład zaczerpnięty z aplikacji Ustawienia dla parametru 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>

W momencie renderowania fragment poprosi o listę ustawień zarówno ze statycznego kodu XML, jak i z ustawień dynamicznych zdefiniowanych w AndroidManifest. Niezależnie od tego, czy PreferenceControllersą zdefiniowane w kodzie Java czy w XML,DashboardFragment zarządza logiką obsługi każdego ustawieniaPreferenceController (omówioną poniżej). Następnie są one wyświetlane w interfejsie jako lista mieszana.

PreferenceController

Wdrażanie PreferenceController na Androidzie 9 i Androidzie 8.x różni się od siebie, co opisujemy w tej sekcji.

PreferenceController w Androidzie 9

PreferenceController zawiera całą logikę interakcji z ustawieniem, w tym wyświetlanie, aktualizowanie, indeksowanie wyszukiwania itp.

Interfejs PreferenceController jest zdefiniowany jako BasePreferenceController. Na przykład zobacz kod w packages/apps/Settings/src/com/android/settings/core/ BasePreferenceController.java

Istnieje kilka podklas BasePreferenceController, z których każda odpowiada konkretnemu stylowi interfejsu, który aplikacja Ustawienia obsługuje domyślnie. Na przykład TogglePreferenceController ma interfejs API, który bezpośrednio odzwierciedla sposób, w jaki użytkownik powinien wchodzić w interakcję z interfejsem ustawień opartym na przełącznikach.

BasePreferenceController ma interfejsy API, takie jak getAvailabilityStatus(), displayPreference(), handlePreferenceTreeClicked(), itp. Szczegółowa dokumentacja każdego interfejsu API znajduje się w klasie interfejsu.

Ograniczenie dotyczące implementacji BasePreferenceController (i jej podklas, takich jak TogglePreferenceController) polega na tym, że sygnatura konstruktora musi być zgodna z jedną z tych opcji:

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

Podczas instalowania preferencji w fragmencie panel udostępnia metodę dołączania PreferenceController przed czasem wyświetlania. W momencie instalacji kontroler jest połączony z fragmentem, dzięki czemu wszystkie przyszłe zdarzenia są wysyłane do kontrolera.

DashboardFragment przechowuje listę PreferenceController na ekranie. W momencie onCreate() fragmentu wszystkie kontrolery są wywoływane dla metody getAvailabilityStatus(), a jeśli zwraca ona wartość „true”, wywoływana jest metoda displayPreference() w celu przetworzenia logiki wyświetlania. getAvailabilityStatus() jest też ważne, aby poinformować platformę Ustawienia, które elementy są dostępne podczas wyszukiwania.

PreferenceController w Androidzie 8.x

PreferenceController zawiera całą logikę interakcji z ustawieniem, w tym wyświetlanie, aktualizowanie, indeksowanie wyszukiwania itp.

W przypadku interakcji związanych z preferencjami interfejs PreferenceController ma interfejsy API isAvailable(), displayPreference(), handlePreferenceTreeClicked() itp. Szczegółową dokumentację każdego interfejsu API można znaleźć w klasie interfejsu.

Podczas instalowania preferencji w fragmencie panel udostępnia metodę dołączania PreferenceController przed czasem wyświetlania. W momencie instalacji kontroler jest połączony z fragmentem, dzięki czemu wszystkie przyszłe zdarzenia są wysyłane do kontrolera.

DashboardFragment przechowuje listę PreferenceControllers na ekranie. W punkcie onCreate() fragmentu wszystkie kontrolery są wywoływane dla metody isAvailable(), a jeśli zwraca ona wartość true, wywoływana jest metoda displayPreference() w celu przetworzenia logiki wyświetlania.

Używanie DashboardFragment

Przenoszenie ustawień ze strony A na stronę B

Jeśli preferencja jest statycznie wymieniona w pliku XML preferencji oryginalnej strony, wykonaj procedurę przenoszenia statycznego dla swojej wersji Androida poniżej. W przeciwnym razie postępuj zgodnie z procedurą przenoszenia dynamicznego w przypadku wersji na Androida.

Statyczne przenoszenie w Androidzie 9

  1. Znajdź pliki XML preferencji dla strony pierwotnej i strony docelowej. Te informacje znajdziesz w metodzie getPreferenceScreenResId() strony.
  2. Usuń preferencję z pliku XML oryginalnej strony.
  3. Dodaj preferencję do pliku XML strony docelowej.
  4. Usuń PreferenceController dla tej preferencji z implementacji w języku Java na oryginalnej stronie. Zwykle jest to createPreferenceControllers(). Kontroler może być zadeklarowany bezpośrednio w pliku XML.

    Uwaga: preferencja może nie mieć wartości PreferenceController.

  5. Utwórz instancję PreferenceController na stronie docelowej w sekcji createPreferenceControllers(). Jeśli element PreferenceController jest zdefiniowany w pliku XML starej strony, zdefiniuj go też w pliku XML nowej strony.

Dynamiczne przenoszenie w Androidzie 9

  1. Sprawdź, w jakiej kategorii znajdują się strona oryginalna i strona docelowa. Te informacje znajdziesz w DashboardFragmentRegistry.
  2. Otwórz plik AndroidManifest.xml, który zawiera ustawienie, które chcesz przenieść, i znajdź wpis Aktywność reprezentujący to ustawienie.
  3. Ustaw wartość metadanych aktywności dla com.android.settings.category na klucz kategorii nowej strony.

Statyczne przenoszenie w Androidzie 8.x

  1. Znajdź pliki XML preferencji dla strony pierwotnej i strony docelowej.
  2. Te informacje znajdziesz w metodzie getPreferenceScreenResId() strony.
  3. Usuń preferencje z pliku XML oryginalnej strony.
  4. Dodaj preferencje do pliku XML strony docelowej.
  5. Usuń PreferenceController dla tej preferencji w implementacji w języku Java na oryginalnej stronie. Zwykle znajduje się w getPreferenceControllers().
  6. Uwaga: może się zdarzyć, że preferencja nie ma wartości PreferenceController.

  7. Utwórz instancję PreferenceController na stronie docelowej w sekcji getPreferenceControllers().

Dynamiczne przenoszenie w Androidzie 8.x

  1. Sprawdź, w jakiej kategorii znajdują się strona oryginalna i strona docelowa. Te informacje znajdziesz w DashboardFragmentRegistry.
  2. Otwórz plik AndroidManifest.xml, który zawiera ustawienie, które chcesz przenieść, i znajdź wpis Aktywność reprezentujący to ustawienie.
  3. Zmień wartość metadanych aktywności na com.android.settings.category, ustaw punkt wartości na klucz kategorii nowej strony.

Tworzenie nowych ustawień na stronie

Jeśli preferencja jest statycznie wymieniona w pliku XML preferencji oryginalnej strony, wykonaj procedurę statyczną opisaną poniżej. W przeciwnym razie postępuj zgodnie z procedurą dynamiczną.

Tworzenie statycznych preferencji

  1. Znajdź pliki XML preferencji dla strony. Te informacje można znaleźć w metodzie getPreferenceScreenResId() na stronie.
  2. Dodaj nowy element Preference w pliku XML. Upewnij się, że ma unikalny android:key.
  3. Określ PreferenceController dla tego ustawienia w metodzie getPreferenceControllers() strony.
    • W Androidzie 8.x i opcjonalnie w Androidzie 9 utwórz instancję PreferenceController dla tego ustawienia w metodzie createPreferenceControllers() strony.

      Jeśli to ustawienie istniało już w innych miejscach, być może jest już dla niego PreferenceController. Możesz ponownie użyć PreferenceController bez tworzenia nowego.

    • Od Androida 9 możesz zadeklarować PreferenceController w XML obok preferencji. Na przykład:
      <Preference
              android:key="reset_dashboard"
              android:title="@string/reset_dashboard_title"
              settings:controller="com.android.settings.system.ResetPreferenceController"/>

Tworzenie dynamicznej preferencji

  1. Sprawdź, w jakiej kategorii znajdują się strona oryginalna i strona docelowa. Te informacje znajdziesz w DashboardFragmentRegistry.
  2. Utwórz nową aktywność w usłudze AndroidManifest
  3. Dodaj do nowej aktywności niezbędne metadane, aby zdefiniować ustawienie. Ustaw wartość metadanych dla com.android.settings.category na tę samą wartość, która została zdefiniowana w kroku 1.

Utwórz nową stronę

  1. Utwórz nowy fragment, dziedzicząc z DashboardFragment.
  2. Określ jego kategorię w DashboardFragmentRegistry.

    Uwaga: ten krok jest opcjonalny. Jeśli na tej stronie nie potrzebujesz żadnych dynamicznych ustawień, nie musisz podawać klucza kategorii.

  3. Wykonaj czynności, aby dodać ustawienia wymagane na tej stronie. Więcej informacji znajdziesz w sekcji Implementacja.

Weryfikacja

  • Uruchom testy Robolectric w Ustawieniach. Wszystkie dotychczasowe i nowe testy powinny zakończyć się powodzeniem.
  • Skompiluj i zainstaluj Ustawienia, a potem ręcznie otwórz modyfikowaną stronę. Strona powinna zostać natychmiast zaktualizowana.