Omówienie nowych interfejsów API

Załóżmy, że chcesz używać kart paska działań jako głównej formy nawigacji najwyższego poziomu w aplikacji. Niestety interfejsy API ActionBar są dostępne tylko w Androidzie 3.0 lub nowszym (poziom interfejsu API 11+). Jeśli więc chcesz rozpowszechniać aplikację na urządzeniach z wcześniejszymi wersjami platformy, musisz udostępnić implementację, która obsługuje nowszy interfejs API, a jednocześnie zapewnia mechanizm rezerwowy korzystający ze starszych interfejsów API.

W tej klasie utworzysz komponent interfejsu użytkownika z kartami, który używa klas abstrakcyjnych z implementacjami specyficznymi dla wersji, aby zapewnić zgodność wsteczną. W tej lekcji opisujemy, jak utworzyć warstwę abstrakcji dla nowych interfejsów API kart jako pierwszy krok w tworzeniu komponentu karty.

Przygotowanie do abstrakcji

Abstrakcja w języku programowania Java polega na utworzeniu co najmniej 1 interfejsu lub klasy abstrakcyjnej w celu ukrycia szczegółów implementacji. W przypadku nowszych interfejsów API Androida możesz użyć abstrakcji do tworzenia komponentów rozpoznających wersję, które używają bieżących interfejsów API na nowszych urządzeniach i starszych, bardziej kompatybilnych interfejsów API na starszych urządzeniach.

Stosując to podejście, najpierw określasz, których nowszych klas chcesz używać w sposób wstecznie kompatybilny, a następnie tworzysz klasy abstrakcyjne na podstawie publicznych interfejsów nowszych klas. Podczas definiowania interfejsów abstrakcji należy jak najwierniej odzwierciedlać nowszy interfejs API. Zwiększa to zgodność z przyszłymi wersjami i ułatwia usunięcie warstwy abstrakcji w przyszłości, gdy nie będzie już potrzebna.

Po utworzeniu klas abstrakcyjnych dla tych nowych interfejsów API można utworzyć dowolną liczbę implementacji i wybrać je w czasie działania. Na potrzeby zgodności wstecznej te implementacje mogą się różnić wymaganym poziomem interfejsu API. Dlatego jedna implementacja może używać niedawno wydanych interfejsów API, a inne – starszych.

Tworzenie abstrakcyjnego interfejsu karty

Aby utworzyć wstecznie kompatybilną wersję kart, musisz najpierw określić, które funkcje i konkretne interfejsy API są wymagane przez aplikację. W przypadku kart sekcji najwyższego poziomu załóżmy, że masz te wymagania funkcjonalne:

  1. Wskaźniki kart powinny wyświetlać tekst i ikonę.
  2. Karty można powiązać z instancją fragmentu.
  3. Aktywność powinna mieć możliwość nasłuchiwania zmian kart.

Przygotowanie tych wymagań z wyprzedzeniem pozwala kontrolować zakres warstwy abstrakcji. Oznacza to, że możesz poświęcić mniej czasu na tworzenie wielu implementacji warstwy abstrakcji i szybciej zacząć korzystać z nowej implementacji zgodnej wstecz.

Kluczowe interfejsy API kart znajdują się w ActionBar i ActionBar.Tab. Są to interfejsy API, które należy abstrahować, aby karty były rozpoznawane przez wersję. Wymagania tego przykładowego projektu wymagają zgodności z Eclair (poziom interfejsu API 5) przy jednoczesnym wykorzystaniu nowych funkcji kart w Honeycomb (poziom interfejsu API 11). Poniżej znajduje się diagram struktury klas obsługujących te 2 implementacje i ich abstrakcyjne klasy bazowe (lub interfejsy).

Abstrakcyjne klasy bazowe i implementacje specyficzne dla wersji.
Rysunek 1. Diagram klas abstrakcyjnych klas bazowych i implementacji specyficznych dla wersji.

Abstrakcyjna karta ActionBar

Zacznij tworzyć warstwę abstrakcji kart, tworząc klasę abstrakcyjną reprezentującą kartę, która odzwierciedla interfejs ActionBar.Tab:

Kotlin

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
    ...
}

Java

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 powiązanie obiektów kart z aktywnościami (nie pokazano w fragmencie kodu), możesz użyć klasy abstrakcyjnej zamiast interfejsu.

Abstrakcyjne metody karty ActionBar

Następnie zdefiniuj klasę abstrakcyjną, która umożliwia tworzenie i dodawanie kart do aktywności, np. ActionBar.newTab() i ActionBar.addTab():

Kotlin

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)

    ...
}

Java

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ą zarówno w starszych, jak i nowszych wersjach platformy.

Warto też przeczytać