Android Data Binding

Merhabalar, bu yazımda arayüz ile modeli birbirine bağlayan Data Binding yapısından bahsedeceğim.

Her seferinde değişken tanımlayıp findViewById() metoduyla atamasını yapıyorsunuzdur. Fakat arayüzdeki eleman sayısı arttığı zaman bu tam bir işkenceye dönüşecektir. İşte o kadar uğraşmak yerine daha akıllıca işimizi halledebileceğimiz Data Binding yapısının faydalarından ve nasıl kullanıldığından bahsedeceğim. Data Binding yerine gelecek olan View Binding yapısını, Canary versiyonuyla deneyimleyebilirsiniz. Buradaki yazımda da View Binding yapısına göz atabilirsiniz.

Şimdi özetle faydalarından bahsedip sonra ayrıntılarına inelim:

  • Yazdığınız kod kısalır, okuması ve kod bakımı kolaylaşır.
  • Model ve arayüz tamamen ayrışıktır.
  • Uygulamadaki tüm arayüz uygulama ilk başladığında bağlanır, uygulamayı kullanırken tekrar tekrar arayüz bağlamaya gerek duymaz.
  • Arayüz elemanlarına erişirken type safety sağlar, hata alma oranınız azalır.

Data Binding yapısı sayesinde UI elemanları ve verilerin birbirlerine bağlanması sağlanır, observabe yapıya sahip olduğudan bağlandığı veri değiştiği anda karşılığındaki arayüz elemanı da güncellenir.

Primitive ve String değişken tipleri varsayılan olarak observable değildir, bu sebeple de bu tipleri Data Binding yaparken kullanırsanız sadece ilk veri bağlantısında arayüzler ayarlanır, sonrasında veri değerleri değiştiğinde veriyle eşleşen arayüz elemanı güncellenemez.

Kullanılan değişkenlerin observable olabilmesi için geliştiriciler Data Binding kütüphanesi içerisine ObservableBoolean, ObservableInt, ObservableDouble gibi bir çok primitive tipin karşılığını ve bir de generic ObservableField oluşturmuşlar.

Bir başka observable yapıya sahip olan ve bağlandığı Activity/Fragment yaşam döngüsüne adapte olan yapı ise LiveData’dır. LiveData yapısı, Room ve WorkManager gibi bir çok mimariyle ile birlikte çalışabilme özelliğine sahiptir.

Projede nasıl kullanılır?
İlk olarak enable edip sync etmeniz gerekiyor.

dataBinding {
    enabled = true
}

İkinci olarak bağlayacağınız arayüz xml’i baştan sonra <layout> tag’iyle sarılmış olması gerekiyor. Binding objesi ancak bu şekilde arayüzü tanıyıp elemanlara bağlanabilir.
Daha sonra <layout> aşağıdaki şemalar giydirmeniz gerekiyor. (LinearLayout’tan kesip tag’in önüne yapıştırabilirsiniz.)

<layout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto">

MainActivity içerisinde binding değişkenine referans alma işlemini gerçekleştirelim.

// import com.example.android.aboutme.databinding.ActivityMainBinding

// define data binding variable
private lateinit var binding: ActivityMainBinding

//inside onCreate(), replace setContentView() with below:
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)

Artık arayüzü modele bağlayabilirsiniz. Aşağıdaki göstereceğim örnekte, MyName isminde bir sınıf oluşturdum ve bağlamak istediğim layout içerisinde değişken olarak atadım. Daha sonra MainActivity içerisinde binding değişkeniyle tüm herşeyimi hallediyorum.

//MyUser.kt
data class MyName(var name: String = "", var nickname: String = "")
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>
        <variable
            name="myName"
            type="com.example.android.aboutme.MyName" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:paddingStart="@dimen/padding"
        android:paddingEnd="@dimen/padding">

        <TextView
            android:id="@+id/name_text"
            style="@style/NameStyle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@={myName.name}"
            android:textAlignment="center" />

        <TextView
            android:id="@+id/nickname_text"
            style="@style/NameStyle"
            android:text="@={myName.nickname}"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textAlignment="center"
            android:visibility="gone" />

        <Button
            android:id="@+id/done_button"
            style="@style/Widget.AppCompat.Button.Colored"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="@dimen/layout_margin"
            android:fontFamily="@font/roboto"
            android:text="@string/done"
            android:textAlignment="center" />

    </LinearLayout>
</layout>
binding.doneButton.setOnClickListener {
            binding. apply {
                myName?.nickname = nicknameEdit.text.toString()
                invalidateAll()
                nicknameEdit.visibility = View.GONE
                doneButton.visibility = View.GONE
                nicknameText.visibility = View.VISIBLE
            }
        }