Android — Data Binding
Data binding kütüphanesi, UI bileşenlerini uygulamanızdaki veri kaynaklarına bağlamanıza olanak tanıyan bir kütüphanedir.
Aşağıdaki kod, bir TextViewi, viewModel
nesnesinin userName
özelliğine bağlamak için findViewById()
öğesini çağırır:
findViewById<TextView>(R.id.sample_text).apply {
text = viewModel.userName
}
Aşağıdaki örnek, doğrudan layout dosyasında TextView
e değer atamak için data binding kütüphanesinin nasıl kullanılacağını gösterir.
<TextView
android:text="@{viewmodel.userName}" />
Layout dosyası içerisinde bileşenleri bağlamak, activity içerisinde bir çok UI framework kullanımı azaltır ve bu bileşenlerin kullanımı kolay hale getirir. Ayrıca uygulamanın performansını iyileştirir ve bellek sızıntılarını ortadan kaldırır.
Kullanımı
Uygulamanızı data binding kullanacak şekilde yapılandırmak için, uygulama modülündeki build.gradle
dosyanızdaki dataBinding
derleme seçeneğini aşağıdaki örnekte gösterildiği gibi etkinleştirin:
android {
...
buildFeatures {
dataBinding true
}
}
Data binding kütüphanesi, layout içinde bulunan viewleri data nesnelerinizle bağlamak için gereken sınıfları otomatik olarak oluşturur. Data binding layout dosyaları biraz farklıdır ve layout
tagi ile başlar. Ardından data
elemanı ve view
root elemanı gelir. Aşağıdaki kod, örnek bir layout dosyasını gösterir:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="user" type="com.example.User"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.firstName}"/>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.lastName}"/>
</LinearLayout>
</layout>
data
içindeki user
değişkeni, bu layout içinde kullanılabilecek bir özelliği tanımlar.
<variable name="user" type="com.example.User" />
Layout içindeki ifadeler, "@{}"
sözdizimi kullanılarak öznitelik özelliklerine yazılır. Burada TextView
metni, user
değişkeninin firstName
özelliğine ayarlanır:
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.firstName}" />
User
adında data classımız olduğunu varsayalım.
data class User(val firstName: String, val lastName: String)
Her layout dosyası için bir binding sınıfı oluşturulur. Varsayılan olarak, sınıfın adı layout dosyasının adını temel alır ve sonuna Binding
ekini ekler. Örneğin: activity_main.xml
layout dosyası için oluşturulacak olan sınıf ActivityMainBinding
‘tir.
Binding oluşturmak için önerilen yöntem:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding: ActivityMainBinding = DataBindingUtil.setContentView(
this, R.layout.activity_main)
binding.user = User("Test", "User")
}
Alternatif olarak, aşağıdaki örnekte gösterildiği gibi bir LayoutInflater
kullanarak görünümü elde edebilirsiniz:
val binding: ActivityMainBinding = ActivityMainBinding.inflate(getLayoutInflater())
Fragment, ListView veya RecyclerView içerisinde data binding kullanıyorsanız, aşağıdaki kod örneğinde gösterildiği gibi binding sınıflarının veya DataBindingUtil
sınıfının inflate()
yöntemlerini kullanmayı tercih edebilirsiniz:
val listItemBinding = ListItemBinding.inflate(layoutInflater, viewGroup, false)
// yada
val listItemBinding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false)
Layout içerisinde bazı operatörler kullanılabilir. Örneğin:
android:text="@{String.valueOf(index + 1)}"
android:visibility="@{age > 13 ? View.GONE : View.VISIBLE}"
android:transitionName='@{"image_" + id}'
Databinding Event Handling
DataBinding kullanırken Event Handling olayını iki şekilde yapabiliriz.
1- Method References kullanarak
2- Listener Bindings kullanarak
Method References
Bir click olayını activity içerisinde yazmak yerine direkt olarak layout içerisinde bind edebiliriz. Bunu yapabilmek için android:onClick
kullanılır. Bu kullanımın en büyük avantajı derleme zamanında işlenmesi, yani belirtilen metod tanımlanmamışsa derleme zamanında hata alınmasıdır. Click işlemini handle eden bir sınıf oluşturalım:
class MyHandlers {
fun onClickFriend(view: View) { ... }
}
onClickFriend()
metodu textView view’ine android:onClick
kullanarak bağlanır.
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="handlers" type="com.example.MyHandlers"/>
<variable name="user" type="com.example.User"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.firstName}"
android:onClick="@{handlers::onClickFriend}"/>
</LinearLayout>
</layout>
Listener Binding
Metod referansı bağlama ile listener bağlama arasındaki en önemli fark metod bağlama event trigger edildiğinde değil veri bağlama aşamasında oluşmasıdır. Listener bağlama, bir olay gerçekleştiğinde çalışan bağlama ifadeleridir. Örneğin, onSaveClick()
yöntemine sahip olan aşağıdaki Presenter
sınıfını düşünün:
class Presenter {
fun onSaveClick(task: Task){}
}
Ardından, click olayını onSaveClick()
metoduna aşağıdaki gibi bağlayabilirsiniz:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="task" type="com.android.example.Task" />
<variable name="presenter" type="com.android.example.Presenter" />
</data>
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent">
<Button android:layout_width="wrap_content" android:layout_height="wrap_content"
android:onClick="@{() -> presenter.onSaveClick(task)}" />
</LinearLayout>
</layout>
Yukarıdaki örnekte, onClick(View) öğesine iletilen view
parametresini tanımlamadık. Listener bağlamaları, listener parametreleri için iki seçenek sunar: metodun tüm parametrelerini yok sayabilir veya hepsini adlandırabilirsiniz. Parametreleri adlandırmayı tercih ederseniz, bunları ifadenizde kullanabilirsiniz. Örneğin, yukarıdaki ifade aşağıdaki gibi yazılabilir:
android:onClick="@{(view) -> presenter.onSaveClick(task)}"
Veya ifadedeki parametreyi kullanmak isterseniz Presenter sınıfını aşağıdaki gibi düzenleyebilirsiniz:
class Presenter {
fun onSaveClick(view: View, task: Task){}
}
android:onClick="@{(theView) -> presenter.onSaveClick(theView, task)}"
Imports, variables, and includes
Data binding kütüphanesi, import, variable ve include gibi özellikler sağlar. Import, layout dosyalarınızın içindeki sınıflara başvurmayı kolaylaştırır. Variable, binding ifadelerinde kullanılabilecek bir özelliği tanımlamanıza olanak tanır. Include, uygulamanız genelinde karmaşık View’leri yeniden kullanmanıza olanak tanır.
<data>
<import type="android.view.View"/>
</data>
Import
Import, layout dosyası içerisinde sınıfları kullanabilmeyi sağlar. data
tagi içerisinde import
anahtar kelimesi ile kullanılır. Aşağıdaki kod örneği, View
sınıfını layout dosyasına aktarır:
<data>
<import type="android.view.View"/>
</data>
View
sınıfını import etmek, binding ifadelerinde kullanabilmemizi sağlar. Aşağıdaki örnek, View
sınıfının VISIBLE
ve GONE
sabitlerinin nasıl kullanıldığını gösterir:
<TextView
android:text="@{user.lastName}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="@{user.isAdult ? View.VISIBLE : View.GONE}"/>
Variable
data
öğesinin içinde birden çok değişken kullanılabilir. Aşağıdaki örnek, user
, image
ve note
değişkenlerini gösterir:
<data>
<import type="android.graphics.drawable.Drawable"/>
<variable name="user" type="com.example.User"/>
<variable name="image" type="Drawable"/>
<variable name="note" type="String"/>
</data>
Include
Değişkenler, include edilen bir layout dosyasına bind edilebilir.
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bind="http://schemas.android.com/apk/res-auto">
<data>
<variable name="user" type="com.example.User"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/name"
bind:user="@{user}"/>
<include layout="@layout/contact"
bind:user="@{user}"/>
</LinearLayout>
</layout>