Załóżmy, że chcesz jako podstawowej formy nawigacji najwyższego poziomu w aplikacji używać kart na pasku działań. Interfejsy API ActionBar
są jednak dostępne tylko w Androidzie 3.0 lub nowszym (poziom API 11 lub nowszy). Dlatego jeśli chcesz udostępnić swoją aplikację na urządzeniach z wcześniejszymi wersjami platformy, musisz udostępnić implementację, która obsługuje nowszy interfejs API, i zapewnić mechanizm zastępczy wykorzystujący starsze interfejsy API.
W tej lekcji utworzysz interfejs użytkownika z kartami, który używa abstrakcyjnych klas z implementacjami zależnymi od wersji w celu zapewnienia zgodności wstecznej. Z tej lekcji dowiesz się, jak utworzyć warstwę abstrakcji dla nowych interfejsów API kart jako pierwszego kroku w kierunku tworzenia komponentu karty.
Przygotuj się do abstrakcji
Abstrakcja w języku programowania Java polega na utworzeniu co najmniej jednego interfejsu lub klas abstrakcyjnych w celu ukrycia szczegółów implementacji. W przypadku nowszych interfejsów API Androida możesz użyć abstrakcji, aby tworzyć komponenty zorientowane na wersję, które korzystają z bieżących interfejsów API na nowszych urządzeniach, lub korzystać ze starszych, bardziej zgodnych interfejsów API na starszych urządzeniach.
W przypadku tej metody najpierw musisz określić, których nowszych klas można używać w sposób zgodny wstecznie, a potem utworzyć klasy abstrakcyjne na podstawie publicznych interfejsów nowych klas. Definiując interfejsy abstrakcji, w miarę możliwości powielaj nowszy interfejs API. Pozwala to zmaksymalizować zgodność wsteczną i ułatwia usunięcie warstwy abstrakcji w przyszłości, gdy nie będzie już potrzebna.
Po utworzeniu klas abstrakcyjnych dla nowych interfejsów API można utworzyć i wybrać dowolną liczbę implementacji w czasie działania. Ze względu na zgodność wsteczną te implementacje mogą się różnić w zależności od wymaganego poziomu interfejsu API. Oznacza to, że w jednej implementacji mogą być używane ostatnio opublikowane interfejsy API, a inne – starsze.
Utwórz abstrakcyjny interfejs karty
Aby utworzyć wersję kart zgodną ze starszymi wersjami, musisz najpierw określić, których funkcji i interfejsów API wymaga Twoja aplikacja. Załóżmy, że w przypadku kart sekcji najwyższego poziomu masz te wymagania funkcjonalne:
- Wskaźniki kart powinny zawierać tekst i ikonę.
- Karty mogą być powiązane z instancją fragmentu.
- Aktywność powinna być w stanie nasłuchiwać zmian na karcie.
Przygotowanie tych wymagań z wyprzedzeniem pozwala kontrolować zakres warstwy abstrakcji. Oznacza to, że możesz poświęcać mniej czasu na tworzenie wielu implementacji warstwy abstrakcji i wcześniej zacząć korzystać z nowej implementacji wstecznej.
Najważniejsze interfejsy API dotyczące kart znajdują się w ActionBar
i ActionBar.Tab
. To są interfejsy API, które należy wyodrębnić, aby uwzględniać wersje kart. Wymagania tego przykładowego projektu wymagają ponownej zgodności z technologią Eclair (poziom interfejsu API 5), a jednocześnie korzystanie z nowych funkcji kart w Honeycomb (poziom API 11). Poniżej znajduje się schemat struktury klas obsługujących te 2 implementacje oraz ich abstrakcyjne klasy podstawowe (lub interfejsy).

Rysunek 1. Diagram klas abstrakcyjnych klas bazowych i implementacji w poszczególnych wersjach.
Abstrakcja ActionBar.Tab
Zacznij tworzyć warstwę abstrakcji kart, tworząc klasę abstrakcyjną reprezentującą kartę, która odzwierciedla interfejs ActionBar.Tab
:
sealed class CompatTab(val tag: String) {
...
abstract fun getText(): CharSequence
abstract fun getIcon(): Drawable
abstract fun getCallback(): CompatTabListener
abstract fun getFragment(): Fragment
abstract fun setText(text: String): CompatTab
abstract fun setIcon(icon: Drawable): CompatTab
abstract fun setCallback(callback: CompatTabListener): CompatTab
abstract fun setFragment(fragment: Fragment): CompatTab
...
}
public abstract class CompatTab {
...
public abstract CompatTab setText(int resId);
public abstract CompatTab setIcon(int resId);
public abstract CompatTab setTabListener(
CompatTabListener callback);
public abstract CompatTab setFragment(Fragment fragment);
public abstract CharSequence getText();
public abstract Drawable getIcon();
public abstract CompatTabListener getCallback();
public abstract Fragment getFragment();
...
}
Aby uprościć implementację typowych funkcji, takich jak łączenie obiektów kart z czynnościami (nie pokazanych w fragmentie kodu), możesz użyć abstrakcyjnej klasy zamiast interfejsu.
Abstrakcyjne metody karty ActionBar
Następnie zdefiniuj abstrakcyjną klasę, która umożliwia tworzenie i dodawanie kart do aktywności, np. ActionBar.newTab()
i ActionBar.addTab()
:
sealed class TabHelper(protected val activity: FragmentActivity) {
...
abstract fun setUp()
fun newTab(tag: String): CompatTab {
// This method is implemented in a later lesson.
}
abstract fun addTab(tab: CompatTab)
...
}
public abstract class TabHelper {
...
public CompatTab newTab(String tag) {
// This method is implemented in a later lesson.
}
public abstract void addTab(CompatTab tab);
...
}
W kolejnych lekcjach utworzysz implementacje TabHelper
i CompatTab
, które działają na starszych i nowszych wersjach platformy.