Android Architecture Components: Data Binding – zagadnienia zaawansowane

Jest to cykl artykułów poświęcony komponentom architektury Androida. Wszystkie artykuły znajdziesz na tej stronie.

pierwszej części poświęconej bibliotece data binding poznaliśmy podstawy. Ten wpis zawiera część bardziej zaawansowanych zagadnień.

Jeszcze raz o podłączeniu danych

Oprócz przedstawionej koncepcji, którą przedstawiłem możemy także łaczyć dane z wyglądem w ten sposób:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
        <TextView
            android:id="@+id/textview"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </LinearLayout>
</layout>

Co ciekawe nie ma tutaj znaczników <Data>, ale za to jest znacznik <Layout> i on w zupełności wystarczy do wygenerowania klasy łączącej. W aktywności możemy uzupełnić dane w następujący sposób:

DatabindingActivityBinding binding = DataBindingUtil.setContentView(this, R.layout.databinding_activity);
binding.textview.setText("Witaj na myenv.net ");

Także możemy skorzystać setXxx() (patrz poprzedni artykuł), aby uzupełnić wszystkie dane za jednym zamachem 😉 W tym przypadku nie mamy dostepu do zmiennych w plikach XML więc bardziej złożone wyrażenia w @{} nie są dostępne. Istnieje jednak możliwość połączenia tych dwóch technik. Z poprzedniej części i przedstawionej powyżej.

Tag <include> w Layout

W układzie XML mamy takie coś:

<include
    android:id="@+id/content_1"
    layout="@layout/content_main" />
<include
    android:id="@+id/content_2"
    layout="@layout/content_main" />

Jak do tego podpiąć się i wstawić wartości?

binding.content1.setNews(news2);
binding.content2.setNews(News3);

Wzorzec dla dołączonych plików ma taki sam wzorzec jak w przypadku widoków. Czyli identyfikator znacznika <include> jest używany jako nazwa pola w klasie. Dołączony układ wygeneruje własną klasę z własnymi polami dla widoków w swoim układzie. Pamiętaj, aby nadać znacznikowi <include> identyfikator w przeciwnym wypadku pole nie zostanie mu nadane. Nic nie stoi na przeszkodzie abyśmy mogli wstawiać wszystkie wartości ręcznie:

binding.content.title.setText("Android Architecture Components: Data Binding");

Zwróć uwagę na to, że zmieniają się nazwy pól. Jeśli nadałeś identyfikatorowi wartość „@+id/content_2” to nazwa pola będzie miała postać content2.

Wyrażenia

Opowiedziałem co nieco o wyrażeniach. Biblioteka umożliwia także wywołanie metod, skorzystanie z operatorów potrójnych i operacje matematyczne. Jak sprawdzić, czy dana wartość jest nullem?

android:text='@{ news.title ?? "Some title" }'

Jest równoznaczne z:

android:text='@{news.title != null ? user.title : "Some title"}'

Chcesz skorzystać z zasobów? Proszę bardzo:

android:padding='@{news.textpadding ? @dimen/textPaddingCompact : @dimen/textPaddingFull, default="10dp"}'

Możesz również użyć formatowania łańcuchów zgodnie ze składnią metod getStringgetQuantityString i getFraction. Po prostu przekazujesz parametry jako argumenty do zasobu.

android:text="@{String.format(@string/comment_format_string, news.comment)}"
<string name="comment_format_string">Count comments: %s</string>

Wyświetli „Count comments: 10”. Zakładając, że news.comment nie będzie nullem 😉 Na chwilę obecną atrybut „style” jeszcze nie działa. W tym przypadku możesz skorzystać z BindingAdapter, który został opisany w poprzednim artykule.

Widoczność widoków

Pokazałem też w jaki sposób wyświetlić etykietkę premium w zależności od tego, czy wartość premium jest true. Sprawdźmy inny przykład w którym chcemy uzyskać dostęp do atrybutów widoku z poziomu wyrażeń.

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <import type="android.view.View" />
    </data>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
        <CheckBox
            android:id="@+id/showSite"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>
        <TextView
            android:id="@+id/site"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:visibility="@{showSite.checked ? View.VISIBLE : View.GONE}" />
    </LinearLayout>
</layout>

Powyższy przykład wyświetla nazwę strony w zależności od tego, czy checkbox jest zaznaczony, czy nie. Odwołujemy się do identyfikatorów w wyrażeniu. Nic trudnego.

Zależne właściwości

Co jeszcze można zmajstrować z @Bindable?, Załóżmy, że w naszej klasie News mamy taki kod:

@Bindable({ "title" , "site" })
public String getFulltitle () {
    return title + " " + site;
}

Adnotacja przyjmuje opcjonalne parametry do zadeklarowania zależności. Teraz metoda getFulltitle, a dokładnie zwraca jej wartośc jest zależna od właściwości title i site. To znaczy, Ilekroć zmieni się którakolwiek z tych wartości, wynik z metody również zostanie zaktualizowany.

Innym sposobem jest wysłanie powiadomienia za pomocą notifyPropertyChanged(BR.fulltitle). Adnotację tą dodajesz do każdego settera właściwości, który jest zależny. W naszym przypadku to title i site.