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 PreferenceController
wymaga, 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 PreferenceController
są 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
- Znajdź pliki XML preferencji dla strony pierwotnej i strony docelowej. Te informacje znajdziesz w metodzie
getPreferenceScreenResId()
strony. - Usuń preferencję z pliku XML oryginalnej strony.
- Dodaj preferencję do pliku XML strony docelowej.
- Usuń
PreferenceController
dla tej preferencji z implementacji w języku Java na oryginalnej stronie. Zwykle jest tocreatePreferenceControllers()
. Kontroler może być zadeklarowany bezpośrednio w pliku XML.Uwaga: preferencja może nie mieć wartości
PreferenceController
. - Utwórz instancję
PreferenceController
na stronie docelowej w sekcjicreatePreferenceControllers()
. Jeśli elementPreferenceController
jest zdefiniowany w pliku XML starej strony, zdefiniuj go też w pliku XML nowej strony.
Dynamiczne przenoszenie w Androidzie 9
- Sprawdź, w jakiej kategorii znajdują się strona oryginalna i strona docelowa. Te informacje znajdziesz w
DashboardFragmentRegistry
. - Otwórz plik
AndroidManifest.xml
, który zawiera ustawienie, które chcesz przenieść, i znajdź wpis Aktywność reprezentujący to ustawienie. - Ustaw wartość metadanych aktywności dla
com.android.settings.category
na klucz kategorii nowej strony.
Statyczne przenoszenie w Androidzie 8.x
- Znajdź pliki XML preferencji dla strony pierwotnej i strony docelowej. Te informacje znajdziesz w metodzie
- Usuń preferencje z pliku XML oryginalnej strony.
- Dodaj preferencje do pliku XML strony docelowej.
- Usuń
PreferenceController
dla tej preferencji w implementacji w języku Java na oryginalnej stronie. Zwykle znajduje się wgetPreferenceControllers()
. - Utwórz instancję
PreferenceController
na stronie docelowej w sekcjigetPreferenceControllers()
.
getPreferenceScreenResId()
strony.
Uwaga: może się zdarzyć, że preferencja nie ma wartości
PreferenceController
.
Dynamiczne przenoszenie w Androidzie 8.x
- Sprawdź, w jakiej kategorii znajdują się strona oryginalna i strona docelowa. Te informacje znajdziesz w
DashboardFragmentRegistry
. - Otwórz plik
AndroidManifest.xml
, który zawiera ustawienie, które chcesz przenieść, i znajdź wpis Aktywność reprezentujący to ustawienie. - 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
- Znajdź pliki XML preferencji dla strony. Te informacje można znaleźć w metodzie getPreferenceScreenResId() na stronie.
- Dodaj nowy element Preference w pliku XML. Upewnij się, że ma unikalny
android:key
. -
Określ
PreferenceController
dla tego ustawienia w metodziegetPreferenceControllers()
strony.- W Androidzie 8.x i opcjonalnie w Androidzie 9 utwórz instancję
PreferenceController
dla tego ustawienia w metodziecreatePreferenceControllers()
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"/>
- W Androidzie 8.x i opcjonalnie w Androidzie 9 utwórz instancję
Tworzenie dynamicznej preferencji
- Sprawdź, w jakiej kategorii znajdują się strona oryginalna i strona docelowa. Te informacje znajdziesz w
DashboardFragmentRegistry
. - Utwórz nową aktywność w usłudze
AndroidManifest
- 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ę
- Utwórz nowy fragment, dziedzicząc z
DashboardFragment
. - 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.
- 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.