Data Binding Kullanımı


   Projelerinizde bol bol RecyclerView kullanıyorsanız ve artık her elemana ne id koymayı düşünmekten, her seferinde findViewById ler ile uğraşmaktan sıkıldıysanız tam aradığınızı buldunuz. DataBinding kütüphanesi API 7 den beri bizlere bu işi kolaylaştırmayı sağlamakta.

    Öncelikle belirtmek isterim ki, DataBinding metodunu hem Activity'de hemde RecyclerView da adapter içinde aktif olarak kullanabilirsiniz. Bugün ben daha çok işe yaradığını düşündüğüm için RecyclerView ile kullanımını göstereceğim.

Hadi başlayalım

   DataBinding metodu mutlaka kullanmamız gereken bir yöntem değildir arkadaşlar.Ancak kullanmanız durumunda size ve projenize sağlayacağı kolaylıkların rahatça farkına varabilirsiniz. Özet olarak DataBinding yöntemi sizin xml tarafında yazdığınız objelerinizi, kod tarafında yaratmadan üzerlerinde işlem yapabilmenizi sağlıyor. İlk olarak gradle'a bizim bu yöntemi kullandığımızı söylemeliyiz ki, derlerken sıkıntı çıkarmasın :)

Aşağıdaki bloğu projenizin gradle dosyasına ekleyin.

    dataBinding {
        enabled = true
    }
        

Pojo yaratma

    Modern çağımızda artık Pojo yaratmadan bir iş yapılamaz hale geldi. Pojo, Plain Old Java Object demektir ve sizin veri modelinizi temsil eder. Özellikle DataBinding, pojonuzun getter'larına bakarak çalışır. Bir objeniz var diyelim -name-, eğer bu pojonuzda getName() ya da name() adında bir method yoksa, DataBinding size aşağıdaki hatayı çakacaktır.

    Could not find accessor bla.bla.bla 

Buna kızmakta haksızda değil aslında. Eğer siz adama nasıl ulaşacağını söylemezseniz oda ulaşamaz ve kızar :) Şimdi yukarıda bahsettiğim özelliklere uyan basit bir pojo yaratalım.

public class places{

    private String name;

    public places(String name) {
        this.name = name;
    }

    //Aşağıdaki method olmazsa 'Could not find accessor packagename.places.name' hatası aşikardır :)

    public String getName(){
        return name;
    }
}
        

Adapter Kısmı

Adapter kısmı işin en kolay kısmı diyebiliriz. Buradaki can alıcı nokta, adapter'ünüzün view holderları yaratılırken, birde o viewlardan ViewDataBinding objesi yaratmak. Bu obje aslında siz ile databinding olayı arasındaki aracı diyebiliriz. Burada kısacası amacımızı belirtiyoruz. Bu viewHolder'a bu objeyi bas diyoruz. Bu viewHolder'ın hangi elemanına ne basacağını da xml tarafında söyleyeceğiz :) Örnek olarak

 public class Row extends RecyclerView.ViewHolder{

        private ViewDataBinding viewDataBinding;

        public Row(View itemView) {
            super(itemView);
            //Burada bu view'ı bind ediyoruz. Bu da bize o viewda DataBinding kullanmamızı sağlıyor.
            this.viewDataBinding = DataBindingUtil.bind(itemView);

        }

        protected void update(int pos) {
            viewDataBinding.setVariable(BR.place, 
mDataSource.get(pos)); viewDataBinding.executePendingBindings(); } }

Buradaki bir diğer önemli nokta ise, BR.place. Arkadaşlar DataBinding'in runtime'da dinamik olarak oluşturduğu BR adında bir class var. Xml tarafında bir variable yarattığınızda bu classa yazılıyor. Dolayısıyla xml tarafında bir variable yaratmadan burada BR. dediğinizde size hiçbişey gelmeyecektir. Öncelikle burada bir "pause" yapıp xml'e gidelim.

Xml Kısmı

DataBinding yöntemindeki xml, alışılagelmiş xml yapısından biraz farklı. Bi kere her zaman xml'in rootu bir Relative,Linear vs.. oluyordu ama burada onların üstünde bir layout tag'ı var. Örnek kod üzerinden anlatalım.

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

    <data>
    <!--Pojomuzu import ettik.-->
        <import type="com.tayfuncesur.databinding.model.places" />

    <!--Bu pojodan bir variable yarattık. -->
        <variable
            name="place"
            type="places" />
    </data>

<!--İşte bunun yaptıktan sonra BR classına artık place adından bir değişken yazıldı bunu artık adapter'de kullanabilirsiniz.-->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:clickable="true"
        android:background="?android:attr/selectableItemBackground">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        <!-- Burada ise yukarıda yaratmış olduğumuz variabledan @{} tagı yardımı ile text'ine ne yazacağımızı belirtiyoruz -->
        android:text="@{place.name}"
        />
    </LinearLayout>
</layout>
        

Adapter'e geri dönüş

Az önce adapter kısmında bir pause yapmıştık. Şimdi devam edebiliriz. Xml kısmında nasıl variable yaratacağımızı gördük. Bu değişkeni yarattıktan sonra

viewDataBinding.setVariable(BR.place,mDataSource.get(pos));
viewDataBinding.executePendingBindings();
        

Burada setVariable bize xmlde yaratmış olduğumuz değişkene, datasource'umuzdaki hangi objenin yazılacagını belirtmemizi sağlıyor.

executePendingBindings

Bu method önemli.executePendingBindings, bindingleri uygular ve viewları değişken değerine update eder.

Daha derine inelim

Bu kısımda biraz daha derine ineceğiz ve Databinding ile başka neder yapabileceğimizi göreceğiz. Arkadaşlar, Xml tarafında az önce belirttiğim gibi import kısmında istediğiniz classı import ederek istediğiniz şeyi yapabilirsiniz. Örnek olarak mesela yazı rengini bi kırmızı bi siyah yapmayı deneyelim. Bunun için anroidin Color classını import etmemiz gerekiyor.


<data>
    <!--Gerekli class'ı import ettik.-->
        <import type="android.graphics.Color" />
        <import type="android.view.View" />
</data>

<TextView
    <!-- Burada ise gördüğünüz gibi @tagına geçtikten sonra klasik java kodu yazabiliyoruz. -->
    android:textColor="@{place.position % 2 == 0 ? Color.RED :
Color.GRAY}" android:visibility="@{place.position % 2 == 0 ? View.VISIBLE :
View.GONE}" />

Event set etme

Şimdi ise örnek olarak nasıl onclickListener set edebileceğimizi anlatacağım. Öncelikle bir interface yaratalım ki onclick event'i olacak olan her viewHolder'ı bu interface'den implement ederek işimizi kolayca ve profesyonelce halledebilelim :)

1.Interface

public interface MyHandler {
    public void onClick(View view);

}
        

2.Xmlde set etme


<data>
    <!--eventi yarattık-->
    <variable
            name="handler"
            type="com.tayfuncesur.databinding.model.MyHandler"/>
</data>

<TextView
    <!-- Burada ise set ediyoruz -->
    android:onClick="@{handler::onClick}"
/>
        

3.Adapter

Kullanmış olduğumuz viewHolder'ı bu interface'den implement edersek, bu event tetiklendiğinde yapacağımız işlemleri yazabiliriz :)

public class Row extends RecyclerView.ViewHolder implements MyHandler{

     	protected void update(int pos) {
     		//Burada bu interface'i de xmlde yarattığımız 
handler'a set etmeliyiz. Aksi halde event tetiklenmeyecektir. viewDataBinding.setVariable(BR.handler, this); } @Override public void onClick(View view) { Toast.makeText(mContext,"onClick",Toast.LENGTH_SHORT)
.show(); } }

BONUS

Bu bölümde size bonus olarak kendi ekstra işlerinizi nasıl yapabileceğinizi bir kaç örnek ile anlatmaya çalışacağım:)
Senaryo 1; Urlden image yüklemek istiyorsunuz. Öncelikle bunun için picasso gibi bir 3.parti kütüphaneye ihtiyacınız var. Onuda hallettik ama nası uygulayacağız. Aşağıdaki kod yardımıyla adapter'ünüzde istediğiniz işleri yapabilirsiniz.


    @BindingAdapter("bind:imageUrl")
    public static void loadImage(ImageView img, String url) {
    //Bu kod,verilen urlden resmi alıp img adlı image'a yükler.
        Picasso.with(imageView.getContext()).load(url).into(img);
    }
        

Xmldeki kullanımı ise şu şekilde


       <ImageView
 <!--Az önce adapter'de yaratmış olduğumuz methodu burada bu şekilde 
kullabiliyoruz.--> app:imageUrl="@{place.photo_url}"/>

Sonuç

   Sonuç olarak, şunu unutmayın arkadaşlar adapter'deki her işi databinding yöntemi ile yapacağınız şartı yoktur. Başınız sıkıştığında klasik yöntem olarak onBindViewHolder'da objenizi yaratarak yine işinizi orada görebilirsiniz. Ancak DataBinding ile ihtiyacınız olan her işi kolayca halledebilirsiniz. İlk başlarda karmaşık ve ne gerek var diyebilirsiniz ancak bir viewHolder'da 15 obje gösterirseniz, hepsine tek tek id tanımlamak, daha sonra onları findViewById ile yaratmak, daha sonrasında ise onlara tek tek dataları set etmek bir süre sonra cidden canınızı sıkmaya başladığında, DataBindingi güle oynaya kullanırsınız:) Örnek proje ve sizler için hazırlamış olduğum quizi en kısa sürede buraya bırakacağım. Eğer bu konuda bir sorun yaşarsanız mail atmaktan çekinmeyin. Yardımcı olmaktan mutluluk duyarım. Şimdilik hoşçakalın...

Örnek projeyi buradan indirebilirsiniz.

Quiz yakında burada olacak.