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.

W 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 getString, getQuantityString 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.

keyboard_arrow_up