Merhaba Arkadaşlar
Mobilhanem.com sitemiz üzerinden anlattığımız / yayınladığımız derslerimize bu dersimizde Android Data Binding kütüphanesini kullanarak Application logic ile layout’ları nasıl daha az kod ile birleştirip kullanabiliriz anlatmaya çalışacağız. Data Binding bize layotlarımız (user interface) ile application logic ve modelimizi birbirine senkron şekilde kullanmamıza olanak sağlar. Hem de bunu en az kod ile yapar.
Bu dersimiz uzun derslerimizden biri olacak. Dersimiz için çok basit bir arayüz hazırlayacağım. Bu arayüzde mobilhanem sitemizdeki bir dersin detayları olacak ve bir buton yardımı ile bu dersi değiştirip başka bir dersin detaylarını göstereceğiz.
Change Tutorial butonuna bastığımız an farklı bir dersin bilgileri ekrana gelecek.
Android Data Binding dersimize başlamadan önce bu işlemleri data binding ve ya herhangi 3.parti bir kütüphane olmadan nasıl yapıyorduk buna bakalım.
Klasik Yöntem
main_activity.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:gravity="center_horizontal"> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@mipmap/mobilhanem_logo" android:layout_marginTop="30dp" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:padding="15dp"> <TextView android:layout_width="100dp" android:layout_height="wrap_content" android:textColor="@color/colorPrimary" android:text="Tutorial Title:"/> <TextView android:id="@+id/tutorial_title" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:padding="15dp"> <TextView android:layout_width="100dp" android:layout_height="wrap_content" android:textColor="@color/colorPrimary" android:text="Tutorial Description:"/> <TextView android:id="@+id/tutorial_desc" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:padding="15dp"> <TextView android:layout_width="100dp" android:layout_height="wrap_content" android:textColor="@color/colorPrimary" android:text="Author Name:"/> <TextView android:id="@+id/author_name" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:padding="15dp"> <TextView android:layout_width="100dp" android:layout_height="wrap_content" android:textColor="@color/colorPrimary" android:text="Number of Reading:"/> <TextView android:id="@+id/number_of_reading" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </LinearLayout> <Button android:id="@+id/change_tutorial" android:layout_width="200dp" android:layout_height="wrap_content" android:text="Change Tutorial"/> </LinearLayout>
Yukarıda basit bir arayüz oluşturduk. Ders için hazırladığımdan fazla özen göstermedim. Sizler kendiniz hazırlarken kod tekrarından ve string ve dimension’ları direk kullanmadan kaçınmalısınız. Bu dersimizin konusunu olmadığı için devam ediyorum.
TutorialData.java
package com.mobilhanem.mobilhanemdatabinding.model; /** * Created by tahakirca on 25/11/2017. */ public class TutorialData { private String tutorialTitle; private String tutorialDescription; private String authorName; private int numberOfReadings; public String getTutorialTitle() { return tutorialTitle; } public TutorialData setTutorialTitle(String tutorialTitle) { this.tutorialTitle = tutorialTitle; return this; } public String getTutorialDescription() { return tutorialDescription; } public TutorialData setTutorialDescription(String tutorialDescription) { this.tutorialDescription = tutorialDescription; return this; } public String getAuthorName() { return authorName; } public TutorialData setAuthorName(String authorName) { this.authorName = authorName; return this; } public int getNumberOfReadings() { return numberOfReadings; } public TutorialData setNumberOfReadings(int numberOfReadings) { this.numberOfReadings = numberOfReadings; return this; } }
Yukarıda ders bilgilerini tutacağımız model class’ı tanımladık.
MainActivity.java
package com.mobilhanem.mobilhanemdatabinding; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.Button; import android.widget.TextView; import com.mobilhanem.mobilhanemdatabinding.model.TutorialData; public class MainActivity extends AppCompatActivity { private TextView tutorial_title,tutorial_description,author_name,number_of_reading; private Button change_tutorial; private TutorialData data; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tutorial_title = (TextView) findViewById(R.id.tutorial_title); tutorial_description = (TextView) findViewById(R.id.tutorial_desc); author_name = (TextView) findViewById(R.id.author_name); number_of_reading = (TextView) findViewById(R.id.number_of_reading); change_tutorial = (Button) findViewById(R.id.change_tutorial); data = new TutorialData().setTutorialTitle("Android DataBinding").setTutorialDescription("Android Data Binding Kütüphanesi Kullanımı").setAuthorName("Taha Kırca").setNumberOfReadings(150); setData(); change_tutorial.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { data = new TutorialData().setTutorialTitle("Git Branch ve Checkout").setTutorialDescription("Git Branch ve Checkout Kullanımı Örnek Uygulama").setAuthorName("Ömer Özkan").setNumberOfReadings(1000); setData(); } }); } private void setData() { tutorial_title.setText(data.getTutorialTitle()); tutorial_description.setText(data.getTutorialDescription()); author_name.setText(data.getAuthorName()); number_of_reading.setText(""+data.getNumberOfReadings()); } }
Yukarıda ise her bir xml elemanımızı tek tek tanımladık. Sonrasında ise her birinin değerini tek tek setData() metotu içinde set ettik. Sonra buton’a tıklanınca data’mızın değerlerini değiştirdik ve tekrardan set ettik. Bizim bu dersimizde çok fazla elemanımız olmadığı için fazla bir yük gibi gözükmesede 10’larca itemin olduğu bir view’i tek tek kodda findById() metotu ile tanımlamak, onlara değer atamak ve her bir değişiklikte tekrar değer atamak cidden zahmetli bir iş ve test driven kod yazanlar için işi daha zor hale getiren bir durum.
Peki bunu nasıl aşacağız. Daha az kod yazarak model , view ve Application Logic ‘i yani Activity’i nasıl birleştireceğiz. Data Binding kullanmadan önce klasik yöntemden daha az kod yazdıran 3.parti bir kütüphane olduğundan söz etmem gerekir. Bu kütüphanenin adı ButterKnife kütüphanesi. ButterKnife kütüphanesi ile daha az kod yazarak bu işi yapabiliriz.İncelemek için tıklayınız.
Eeee madem bu kütüphane bu işi yapıyor bu dersi neden yaptık diyorsanız, çünkü Data Binding ile daha da az kod yazarak bu işi yapabiliyoruz. O zaman başlayalım asıl dersimizin konusuna.
Android Data Binding Kütüphanesi
Öncelikle build.gradle dosyamız içinde android attribute altında data binding kütüphanesi kullanmaya izin vermeliyiz.
android { ... dataBinding { enabled = true } }
Bu izni verdikten sonra artık kullanmaya başlayabiliriz.
main_activity.xml
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="tutorial" type="com.mobilhanem.mobilhanemdatabinding.model.TutorialData"/> <!--Açıklama : name = tutorial verdik artık bu modele tutorial adı ile ulaşacağız --> </data> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:gravity="center_horizontal"> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@mipmap/mobilhanem_logo" android:layout_marginTop="30dp" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:padding="15dp"> <TextView android:layout_width="100dp" android:layout_height="wrap_content" android:textColor="@color/colorPrimary" android:text="Tutorial Title:"/> <TextView android:id="@+id/tutorial_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{tutorial.tutorialTitle}"/> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:padding="15dp"> <TextView android:layout_width="100dp" android:layout_height="wrap_content" android:textColor="@color/colorPrimary" android:text="Tutorial Description:"/> <TextView android:id="@+id/tutorial_desc" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{tutorial.tutorialDescription}"/> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:padding="15dp"> <TextView android:layout_width="100dp" android:layout_height="wrap_content" android:textColor="@color/colorPrimary" android:text="Author Name:"/> <TextView android:id="@+id/author_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{tutorial.authorName}"/> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:padding="15dp"> <TextView android:layout_width="100dp" android:layout_height="wrap_content" android:textColor="@color/colorPrimary" android:text="Number of Reading:"/> <TextView android:id="@+id/number_of_reading" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{String.valueOf(tutorial.numberOfReadings)}"/> <!-- Açıklama : numberOfReadings int değer olduğu için String.valueOf metotu içinde yazdık--> </LinearLayout> </LinearLayout> </layout>
Yukarıda gördüğünüz gibi direk bir Linear , Relative ve ya Constraint Layout ile değil <layout> tagı ile başladık ve kullanacağımız model’i xml’imize data tagı altında bildirmiş olduk.
<data> <variable name="tutorial" type="com.mobilhanem.mobilhanemdatabinding.model.TutorialData"/> </data>
Biz burada yukarıda klasik yöntemde kullandığımız TutorialData’nın aynısı değişiklik yapmadan kullanıyoruz.
Sonrasında textview.setText işlemlerini activity’de yapmak yerine burada textView’in TutorialData’nın hangi değişkenini kullanacağını android:text="@{tutorial.authorName}"
şeklinde bu textView’in TutorialData’nın authorName değişkenini kullanacağını söylüyoruz. Bunun gibi tüm textView’leri hangi değişkenleri kullanacağını yukarıdaki xml içinde belirtiyoruz.
Gelelim activity içinde ne yaptığımıza:
MainActivity.java
package com.mobilhanem.mobilhanemdatabinding; import android.databinding.DataBindingUtil; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import com.mobilhanem.mobilhanemdatabinding.databinding.ActivityMainBinding; import com.mobilhanem.mobilhanemdatabinding.model.TutorialData; public class MainActivity extends AppCompatActivity { private TutorialData data; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ActivityMainBinding bindings = DataBindingUtil.setContentView(this, R.layout.activity_main); //data'larımızı tutacağımız data modelimizi set ediyoruz. data = new TutorialData().setTutorialTitle("Android DataBinding").setTutorialDescription("Android Data Binding Kütüphanesi Kullanımı").setAuthorName("Taha Kırca").setNumberOfReadings(150); bindings.setTutorial(data); //burada setTutorial dememizin sebebi xml'imizde data tagı içinde tutorial kullanmış olmamızdır. Eğer data tagı içinde name kısmına taha verseydik bu metotumuzun adı setTaha() olmalıydı } }
Klasik yöntemdeki gibi satırlarca tanımlamalarla uğraşmadık. Aynı zamanda setText metotlarını activity içinde tanımlamak zorunda kalmadık. 10’larca satır koddan kurtulduk diyebiliriz. Çok daha büyük projelerde yüzlerce satır koddan kurtulmamızı sağlayacaktır.
Yukarıdaki kodu çalıştırdığımız zaman dataların otomatik olarak textviewlere set edildiğini göreceksiniz.
Ama yukarıdaki kodda TutorialData da herhangi bir güncelleme yapmadık. Yani yukarıdaki kodda sadece bir dersi gösterebiliyoruz. Change Tutorial butonumuzun bir işlevselliği yok. Bunun için önce data binding kullanarak nasıl buton’a clicklistener tanımlayabiliriz ona bakalım.
Databinding Event Handling
DataBinding kullanırken Event Handling olayını iki şekilde yapabiliriz.
1- Method References kullanarak
2- Listener Bindings kullanarak
Ben bu dersimde basit yöntem olan 1.sini anlatacağım. 2. sini de öğrenmek istiyorsanız tıklayınız.
Öncelikle activity’mize butonumuz tıklandığında çağırılacak methodu tanımlayalım.
import android.databinding.DataBindingUtil; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import com.mobilhanem.mobilhanemdatabinding.databinding.ActivityMainBinding; import com.mobilhanem.mobilhanemdatabinding.model.TutorialData; public class MainActivity extends AppCompatActivity { private TutorialData data; private ActivityMainBinding bindings; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); bindings = DataBindingUtil.setContentView(this, R.layout.activity_main); bindings.setActivity(this); data = new TutorialData().setTutorialTitle("Android DataBinding").setTutorialDescription("Android Data Binding Kütüphanesi Kullanımı").setAuthorName("Taha Kırca").setNumberOfReadings(150); bindings.setTutorial(data); } public void changeTutorial(View view) { //çağıralacak method data.setTutorialTitle("Git Branch ve Checkout").setTutorialDescription("Git Branch ve Checkout Kullanımı Örnek Uygulama").setAuthorName("Ömer Özkan").setNumberOfReadings(1000); bindings.setTutorial(data); } }
changeTutorial(View view) butona tıklandığı zaman çağırılacak metotumuz.
Layoutumuzun ise aşağıdaki gibi olmaktadır.
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="tutorial" type="com.mobilhanem.mobilhanemdatabinding.model.TutorialData"/> <variable name="activity" type="com.mobilhanem.mobilhanemdatabinding.MainActivity"/> </data> . . . . <!-- Butonumuz--> <Button android:id="@+id/change_tutorial" android:layout_width="200dp" android:layout_height="wrap_content" android:onClick="@{activity::changeTutorial}" android:text="Change Tutorial"/> </LinearLayout> </layout>
Yukarıdaki yaptığımız işlemleri kısaca özetleyelim. Databinding kullanırken herhangi bir tıklama olayını ( farklı bir event’ta olabilir), bunu activity’mize aktarmak için öncelikle activity’mizde çağırılacak methodu tanımladık , sonrasında bu activity’mizi layoutumuza aşağıdaki gibi variable olarak tanımladık.
<data> <variable name="activity" type="com.mobilhanem.mobilhanemdatabinding.MainActivity"/> </data>
Artık bizim layoutumuz içinden activity ile ilgili işlemler “activity” değişkeni ile yapılacak. Çünkü variable name’miz “activity” tanımladık.
Sonrasında butona tıklanıldığında ilgili methodu aşağıdaki gibi çağırıyoruz.
<Button android:id="@+id/change_tutorial" android:layout_width="200dp" android:layout_height="wrap_content" android:onClick="@{activity::changeTutorial}" <!-- methodu çağıran yer --> android:text="Change Tutorial"/>
method içinde ne yaptığımıza bakacak olursak
public void changeTutorial(View view) { data.setTutorialTitle("Git Branch ve Checkout").setTutorialDescription("Git Branch ve Checkout Kullanımı Örnek Uygulama").setAuthorName("Ömer Özkan").setNumberOfReadings(1000); bindings.setTutorial(data); }
data objemizi tekrardan set ediyoruz ve tekrardan bindings.setTutorial(data)
diyerek datamızı ekranda gösteriyoruz.
Peki biz her data değiştiği zaman setTutorial()
methodunu çağırmak zorundamıyız. Yani data objemizin herhangi bir değişkeni değiştiği zamansetTutorial
methodunu çağırmadan ekranımızda ki değerleri update edemez miyiz ?
Observable Objects
Yukarıdaki sorunun cevabı evet edebiliriz. Yani mainActivity’mizde sadece data objemizi güncelleyerek ekranımızı da güncelleyebiliriz. Bunu yapmamız için modelimizi yani TutorailData class’ımızı biraz değiştirmemiz gerekiyor. BaseObservable classını extend ederek aşağıdaki gibi güncellememiz gerekiyor.
import android.databinding.BaseObservable; import android.databinding.Bindable; import com.mobilhanem.mobilhanemdatabinding.BR; /** * Created by tahakirca on 25/11/2017. */ public class TutorialData extends BaseObservable { private String tutorialTitle; private String tutorialDescription; private String authorName; private int numberOfReadings; @Bindable public String getTutorialTitle() { return this.tutorialTitle; } public TutorialData setTutorialTitle(String tutorialTitle) { this.tutorialTitle = tutorialTitle; notifyPropertyChanged(BR.tutorialTitle); //data değişti return this; } @Bindable public String getTutorialDescription() { return this.tutorialDescription; } public TutorialData setTutorialDescription(String tutorialDescription) { this.tutorialDescription = tutorialDescription; notifyPropertyChanged(BR.tutorialDescription);//data değişti return this; } @Bindable public String getAuthorName() { return this.authorName; } public TutorialData setAuthorName(String authorName) { this.authorName = authorName; notifyPropertyChanged(BR.authorName);//data değişti return this; } @Bindable public int getNumberOfReadings() { return this.numberOfReadings; } public TutorialData setNumberOfReadings(int numberOfReadings) { this.numberOfReadings = numberOfReadings; notifyPropertyChanged(BR.numberOfReadings);//data değişti return this; } }
Yukarıdaki kodda , kendi değeri değiştiğinde ekrandaki değerininde değişmesini istediğimiz değişkenin getter methodunun başına @Bindable annotation ekliyoruz ve setter methodlarına ise bir değişiklik olduğunda çağırılacak notifyPropertyChanged() methodunu ekliyoruz. @Bindable eklemediğimizde ve ya notifyPropertyChanged methodunu çağırmadığımızda işlemler gerçekleşmeyecektir. notifyPropertyChanged() içindeki gönderdiğim BR class’ı ise otomatik generate edilecek bir class’tır.
Bu işlemleri yaptıktan sonra artık data objemizi değiştirdiğimiz an ekrandaki değerlerde otomatik olarak değişecektir. Aşağıdaki işlemi yaptıktan sonra tekrardan setTutorial() metodunu çağırmamıza gerek yoktur. Kendisi otomatik olarak ekrandaki değerini değiştirecektir.
public void changeTutorial(View view) { data.setTutorialTitle("Git Branch ve Checkout").setTutorialDescription("Git Branch ve Checkout Kullanımı Örnek Uygulama").setAuthorName("Ömer Özkan").setNumberOfReadings(1000); }
Tüm değerleride değiştirmemize gerek yoktur. Aşağıda kod çalıştığı zaman ekran da sadece okunma sayısı değeri değişecektir.
data.setNumberOfReadings(1500);
Özet
Büyük projelerde sürekli findById() kullanarak itemleri Activity’e tanıtmak hem çok fazla kod yazmamıza sebep oluyor hem de test driven kod yazmanın önünde bir zorluk olarak duruyor. Data binding kullanarak hem kod hamallığından kurtulabilir hem de test driven kod yazmak için gerekli olan Application logic ile layout’ları birbirinden ayırabiliriz. Ayrıca sadece model data’mızı güncelleyerek ekrandaki componentlerimizi de güncelleyebiliriz. Kodun son halini paylaşacağım. Sizlerde inceleyerek projelerinizde kullanabilirsiniz.
Arkadaşlar mevcut bir projeniz varsa Data Binding’e geçirmek pek kolay olmayacaktır. Burda tercih sizindir. Fakat yeni başladığınız bir projenize kesinlikle Data Binding kullanarak başlamanızı öneririm. Ayrıca iş görüşmelerinde sizlere verilen ödevleri kesinlikle data binding ile yazmanızı öneririm 🙂 Ben bu dersimde elimden geldiğince basit bir biçimde anlatmaya çalıştım. Çok daha fazla özelliği bulunan data binding’i Android’in kendi sitesinden de incelemenizi kesinlikle tavsiye ederim.
Android Data Binding Kütüphanesi’nin kullanımını anlattığımız dersimizin sonuna geldik. Umarım sizler için yararlı olmuştur. Konu hakkında soru , görüş ve yorumlarını konu altından ve ya SoruCevap sitemizden sorabilirsiniz.
Android Data Binding Kütüphanesi
Sıfırdan Android derslerimiz için tıklayınız.
6
Merhabalar Taha bey. Benim bir sorunum oldu ve hiç bir yerde çözümünü bulamadım. Projeyi build ettiğim zaman databinding tarafından oluşturulan *Binding.java dosyalarında import kısımlarında import bla.bla.ViewModels.BlaViewModel; gelmesi gerekirken bende import bla.bla.ViewModels; geliyor ve altta kullanımına da ViewModels.BlaViewModel şeklinde geliyor. Hata olarak error: cannot find symbol class ViewModels error: package ViewModels does not exist geliyor. İyi günler. İyi çalışmalar.
dostum aynı sorun bendede var.. ViewModel classını projenin içerisinde at ben öyle düzelttim.. Yani klasör içerisinde olursa hata veriyor şimdilik bu çözümü buldum düzeltirsen burdan bilgi verirsin teşekkürler